Merge branch 'mini_refactoring' of https://github.com/knowledge4igor/Simple-Web-Server
This commit is contained in:
commit
99cc6d9ad3
5 changed files with 53 additions and 46 deletions
|
|
@ -6,6 +6,8 @@
|
|||
#include <random>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
#include <limits>
|
||||
#include <cstddef>
|
||||
|
||||
#ifdef USE_STANDALONE_ASIO
|
||||
#include <asio.hpp>
|
||||
|
|
@ -42,7 +44,7 @@ namespace SimpleWeb {
|
|||
friend class ClientBase<socket_type>;
|
||||
|
||||
public:
|
||||
size_t size() noexcept {
|
||||
std::size_t size() noexcept {
|
||||
return streambuf.size();
|
||||
}
|
||||
/// Convenience function to return std::string. The stream buffer is consumed.
|
||||
|
|
@ -68,7 +70,7 @@ namespace SimpleWeb {
|
|||
|
||||
asio::streambuf streambuf;
|
||||
|
||||
Response(size_t max_response_streambuf_size) noexcept : streambuf(max_response_streambuf_size), content(streambuf) {}
|
||||
Response(std::size_t max_response_streambuf_size) noexcept : streambuf(max_response_streambuf_size), content(streambuf) {}
|
||||
|
||||
public:
|
||||
std::string http_version, status_code;
|
||||
|
|
@ -91,7 +93,7 @@ namespace SimpleWeb {
|
|||
long timeout_connect = 0;
|
||||
/// Maximum size of response stream buffer. Defaults to architecture maximum.
|
||||
/// Reaching this limit will result in a message_size error code.
|
||||
size_t max_response_streambuf_size = static_cast<size_t>(-1);
|
||||
std::size_t max_response_streambuf_size = std::numeric_limits<std::size_t>::max();
|
||||
/// Set proxy server (server:port)
|
||||
std::string proxy_server;
|
||||
};
|
||||
|
|
@ -140,7 +142,7 @@ namespace SimpleWeb {
|
|||
|
||||
class Session {
|
||||
public:
|
||||
Session(size_t max_response_streambuf_size, std::shared_ptr<Connection> connection, std::unique_ptr<asio::streambuf> request_streambuf) noexcept
|
||||
Session(std::size_t max_response_streambuf_size, std::shared_ptr<Connection> connection, std::unique_ptr<asio::streambuf> request_streambuf) noexcept
|
||||
: connection(std::move(connection)), request_streambuf(std::move(request_streambuf)), response(new Response(max_response_streambuf_size)) {}
|
||||
|
||||
std::shared_ptr<Connection> connection;
|
||||
|
|
@ -230,7 +232,7 @@ namespace SimpleWeb {
|
|||
connection->in_use = false;
|
||||
|
||||
// Remove unused connections, but keep one open for HTTP persistent connection:
|
||||
size_t unused_connections = 0;
|
||||
std::size_t unused_connections = 0;
|
||||
for(auto it = this->connections.begin(); it != this->connections.end();) {
|
||||
if(ec && connection == *it)
|
||||
it = this->connections.erase(it);
|
||||
|
|
@ -289,7 +291,7 @@ namespace SimpleWeb {
|
|||
connection->in_use = false;
|
||||
|
||||
// Remove unused connections, but keep one open for HTTP persistent connection:
|
||||
size_t unused_connections = 0;
|
||||
std::size_t unused_connections = 0;
|
||||
for(auto it = this->connections.begin(); it != this->connections.end();) {
|
||||
if(ec && connection == *it)
|
||||
it = this->connections.erase(it);
|
||||
|
|
@ -356,7 +358,7 @@ namespace SimpleWeb {
|
|||
|
||||
std::shared_ptr<ScopeRunner> handler_runner;
|
||||
|
||||
size_t concurrent_synchronous_requests = 0;
|
||||
std::size_t concurrent_synchronous_requests = 0;
|
||||
std::mutex concurrent_synchronous_requests_mutex;
|
||||
|
||||
ClientBase(const std::string &host_port, unsigned short default_port) noexcept : handler_runner(new ScopeRunner()) {
|
||||
|
|
@ -420,7 +422,7 @@ namespace SimpleWeb {
|
|||
|
||||
std::pair<std::string, unsigned short> parse_host_port(const std::string &host_port, unsigned short default_port) const noexcept {
|
||||
std::pair<std::string, unsigned short> parsed_host_port;
|
||||
size_t host_end = host_port.find(':');
|
||||
std::size_t host_end = host_port.find(':');
|
||||
if(host_end == std::string::npos) {
|
||||
parsed_host_port.first = host_port;
|
||||
parsed_host_port.second = default_port;
|
||||
|
|
@ -434,7 +436,7 @@ namespace SimpleWeb {
|
|||
|
||||
void write(const std::shared_ptr<Session> &session) {
|
||||
session->connection->set_timeout();
|
||||
asio::async_write(*session->connection->socket, session->request_streambuf->data(), [this, session](const error_code &ec, size_t /*bytes_transferred*/) {
|
||||
asio::async_write(*session->connection->socket, session->request_streambuf->data(), [this, session](const error_code &ec, std::size_t /*bytes_transferred*/) {
|
||||
session->connection->cancel_timeout();
|
||||
auto lock = session->connection->handler_runner->continue_lock();
|
||||
if(!lock)
|
||||
|
|
@ -448,7 +450,7 @@ namespace SimpleWeb {
|
|||
|
||||
void read(const std::shared_ptr<Session> &session) {
|
||||
session->connection->set_timeout();
|
||||
asio::async_read_until(*session->connection->socket, session->response->streambuf, "\r\n\r\n", [this, session](const error_code &ec, size_t bytes_transferred) {
|
||||
asio::async_read_until(*session->connection->socket, session->response->streambuf, "\r\n\r\n", [this, session](const error_code &ec, std::size_t bytes_transferred) {
|
||||
session->connection->cancel_timeout();
|
||||
auto lock = session->connection->handler_runner->continue_lock();
|
||||
if(!lock)
|
||||
|
|
@ -459,7 +461,7 @@ namespace SimpleWeb {
|
|||
}
|
||||
if(!ec) {
|
||||
session->connection->attempt_reconnect = true;
|
||||
size_t num_additional_bytes = session->response->streambuf.size() - bytes_transferred;
|
||||
std::size_t num_additional_bytes = session->response->streambuf.size() - bytes_transferred;
|
||||
|
||||
if(!ResponseMessage::parse(session->response->content, session->response->http_version, session->response->status_code, session->response->header)) {
|
||||
session->callback(session->connection, make_error_code::make_error_code(errc::protocol_error));
|
||||
|
|
@ -471,7 +473,7 @@ namespace SimpleWeb {
|
|||
auto content_length = stoull(header_it->second);
|
||||
if(content_length > num_additional_bytes) {
|
||||
session->connection->set_timeout();
|
||||
asio::async_read(*session->connection->socket, session->response->streambuf, asio::transfer_exactly(content_length - num_additional_bytes), [this, session](const error_code &ec, size_t /*bytes_transferred*/) {
|
||||
asio::async_read(*session->connection->socket, session->response->streambuf, asio::transfer_exactly(content_length - num_additional_bytes), [this, session](const error_code &ec, std::size_t /*bytes_transferred*/) {
|
||||
session->connection->cancel_timeout();
|
||||
auto lock = session->connection->handler_runner->continue_lock();
|
||||
if(!lock)
|
||||
|
|
@ -496,7 +498,7 @@ namespace SimpleWeb {
|
|||
}
|
||||
else if(session->response->http_version < "1.1" || ((header_it = session->response->header.find("Session")) != session->response->header.end() && header_it->second == "close")) {
|
||||
session->connection->set_timeout();
|
||||
asio::async_read(*session->connection->socket, session->response->streambuf, [this, session](const error_code &ec, size_t /*bytes_transferred*/) {
|
||||
asio::async_read(*session->connection->socket, session->response->streambuf, [this, session](const error_code &ec, std::size_t /*bytes_transferred*/) {
|
||||
session->connection->cancel_timeout();
|
||||
auto lock = session->connection->handler_runner->continue_lock();
|
||||
if(!lock)
|
||||
|
|
@ -552,7 +554,7 @@ namespace SimpleWeb {
|
|||
chunked_stream << &session->response->streambuf;
|
||||
}
|
||||
session->connection->set_timeout();
|
||||
asio::async_read_until(*session->connection->socket, *chunked_streambuf, "\r\n", [this, session, chunked_streambuf, tmp_streambuf](const error_code &ec, size_t bytes_transferred) {
|
||||
asio::async_read_until(*session->connection->socket, *chunked_streambuf, "\r\n", [this, session, chunked_streambuf, tmp_streambuf](const error_code &ec, std::size_t bytes_transferred) {
|
||||
session->connection->cancel_timeout();
|
||||
auto lock = session->connection->handler_runner->continue_lock();
|
||||
if(!lock)
|
||||
|
|
@ -605,7 +607,7 @@ namespace SimpleWeb {
|
|||
|
||||
if((2 + length) > num_additional_bytes) {
|
||||
session->connection->set_timeout();
|
||||
asio::async_read(*session->connection->socket, *chunked_streambuf, asio::transfer_exactly(2 + length - num_additional_bytes), [this, session, chunked_streambuf, post_process](const error_code &ec, size_t /*bytes_transferred*/) {
|
||||
asio::async_read(*session->connection->socket, *chunked_streambuf, asio::transfer_exactly(2 + length - num_additional_bytes), [this, session, chunked_streambuf, post_process](const error_code &ec, std::size_t /*bytes_transferred*/) {
|
||||
session->connection->cancel_timeout();
|
||||
auto lock = session->connection->handler_runner->continue_lock();
|
||||
if(!lock)
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
#define CLIENT_HTTPS_HPP
|
||||
|
||||
#include "client_http.hpp"
|
||||
#include <cstddef>
|
||||
|
||||
#ifdef USE_STANDALONE_ASIO
|
||||
#include <asio/ssl.hpp>
|
||||
|
|
@ -70,7 +71,7 @@ namespace SimpleWeb {
|
|||
write_stream << "CONNECT " + host_port + " HTTP/1.1\r\n"
|
||||
<< "Host: " << host_port << "\r\n\r\n";
|
||||
session->connection->set_timeout(this->config.timeout_connect);
|
||||
asio::async_write(session->connection->socket->next_layer(), *write_buffer, [this, session, write_buffer](const error_code &ec, size_t /*bytes_transferred*/) {
|
||||
asio::async_write(session->connection->socket->next_layer(), *write_buffer, [this, session, write_buffer](const error_code &ec, std::size_t /*bytes_transferred*/) {
|
||||
session->connection->cancel_timeout();
|
||||
auto lock = session->connection->handler_runner->continue_lock();
|
||||
if(!lock)
|
||||
|
|
@ -78,7 +79,7 @@ namespace SimpleWeb {
|
|||
if(!ec) {
|
||||
std::shared_ptr<Response> response(new Response(this->config.max_response_streambuf_size));
|
||||
session->connection->set_timeout(this->config.timeout_connect);
|
||||
asio::async_read_until(session->connection->socket->next_layer(), response->streambuf, "\r\n\r\n", [this, session, response](const error_code &ec, size_t /*bytes_transferred*/) {
|
||||
asio::async_read_until(session->connection->socket->next_layer(), response->streambuf, "\r\n\r\n", [this, session, response](const error_code &ec, std::size_t /*bytes_transferred*/) {
|
||||
session->connection->cancel_timeout();
|
||||
auto lock = session->connection->handler_runner->continue_lock();
|
||||
if(!lock)
|
||||
|
|
|
|||
|
|
@ -9,6 +9,8 @@
|
|||
#include <sstream>
|
||||
#include <thread>
|
||||
#include <unordered_set>
|
||||
#include <limits>
|
||||
#include <cstddef>
|
||||
|
||||
#ifdef USE_STANDALONE_ASIO
|
||||
#include <asio.hpp>
|
||||
|
|
@ -82,7 +84,7 @@ namespace SimpleWeb {
|
|||
}
|
||||
|
||||
public:
|
||||
size_t size() noexcept {
|
||||
std::size_t size() noexcept {
|
||||
return streambuf.size();
|
||||
}
|
||||
|
||||
|
|
@ -90,7 +92,7 @@ namespace SimpleWeb {
|
|||
void send(const std::function<void(const error_code &)> &callback = nullptr) noexcept {
|
||||
session->connection->set_timeout(timeout_content);
|
||||
auto self = this->shared_from_this(); // Keep Response instance alive through the following async_write
|
||||
asio::async_write(*session->connection->socket, streambuf, [self, callback](const error_code &ec, size_t /*bytes_transferred*/) {
|
||||
asio::async_write(*session->connection->socket, streambuf, [self, callback](const error_code &ec, std::size_t /*bytes_transferred*/) {
|
||||
self->session->connection->cancel_timeout();
|
||||
auto lock = self->session->connection->handler_runner->continue_lock();
|
||||
if(!lock)
|
||||
|
|
@ -156,7 +158,7 @@ namespace SimpleWeb {
|
|||
friend class ServerBase<socket_type>;
|
||||
|
||||
public:
|
||||
size_t size() noexcept {
|
||||
std::size_t size() noexcept {
|
||||
return streambuf.size();
|
||||
}
|
||||
/// Convenience function to return std::string. The stream buffer is consumed.
|
||||
|
|
@ -182,7 +184,7 @@ namespace SimpleWeb {
|
|||
friend class Session;
|
||||
|
||||
asio::streambuf streambuf;
|
||||
Request(size_t max_request_streambuf_size, const std::string &remote_endpoint_address = std::string(), unsigned short remote_endpoint_port = 0) noexcept
|
||||
Request(std::size_t max_request_streambuf_size, const std::string &remote_endpoint_address = std::string(), unsigned short remote_endpoint_port = 0) noexcept
|
||||
: streambuf(max_request_streambuf_size), content(streambuf), remote_endpoint_address(remote_endpoint_address), remote_endpoint_port(remote_endpoint_port) {}
|
||||
|
||||
public:
|
||||
|
|
@ -248,7 +250,7 @@ namespace SimpleWeb {
|
|||
|
||||
class Session {
|
||||
public:
|
||||
Session(size_t max_request_streambuf_size, std::shared_ptr<Connection> connection) noexcept : connection(std::move(connection)) {
|
||||
Session(std::size_t max_request_streambuf_size, std::shared_ptr<Connection> connection) noexcept : connection(std::move(connection)) {
|
||||
try {
|
||||
auto remote_endpoint = this->connection->socket->lowest_layer().remote_endpoint();
|
||||
request = std::shared_ptr<Request>(new Request(max_request_streambuf_size, remote_endpoint.address().to_string(), remote_endpoint.port()));
|
||||
|
|
@ -273,14 +275,14 @@ namespace SimpleWeb {
|
|||
unsigned short port;
|
||||
/// If io_service is not set, number of threads that the server will use when start() is called.
|
||||
/// Defaults to 1 thread.
|
||||
size_t thread_pool_size = 1;
|
||||
std::size_t thread_pool_size = 1;
|
||||
/// Timeout on request handling. Defaults to 5 seconds.
|
||||
long timeout_request = 5;
|
||||
/// Timeout on content handling. Defaults to 300 seconds.
|
||||
long timeout_content = 300;
|
||||
/// Maximum size of request stream buffer. Defaults to architecture maximum.
|
||||
/// Reaching this limit will result in a message_size error code.
|
||||
size_t max_request_streambuf_size = static_cast<size_t>(-1);
|
||||
std::size_t max_request_streambuf_size = std::numeric_limits<std::size_t>::max();
|
||||
/// IPv4 address in dotted decimal form or IPv6 address in hexadecimal notation.
|
||||
/// If empty, the address will be any address.
|
||||
std::string address;
|
||||
|
|
@ -342,7 +344,7 @@ namespace SimpleWeb {
|
|||
if(internal_io_service) {
|
||||
// If thread_pool_size>1, start m_io_service.run() in (thread_pool_size-1) threads for thread-pooling
|
||||
threads.clear();
|
||||
for(size_t c = 1; c < config.thread_pool_size; c++) {
|
||||
for(std::size_t c = 1; c < config.thread_pool_size; c++) {
|
||||
threads.emplace_back([this]() {
|
||||
this->io_service->run();
|
||||
});
|
||||
|
|
@ -418,7 +420,7 @@ namespace SimpleWeb {
|
|||
|
||||
void read_request_and_content(const std::shared_ptr<Session> &session) {
|
||||
session->connection->set_timeout(config.timeout_request);
|
||||
asio::async_read_until(*session->connection->socket, session->request->streambuf, "\r\n\r\n", [this, session](const error_code &ec, size_t bytes_transferred) {
|
||||
asio::async_read_until(*session->connection->socket, session->request->streambuf, "\r\n\r\n", [this, session](const error_code &ec, std::size_t bytes_transferred) {
|
||||
session->connection->cancel_timeout();
|
||||
auto lock = session->connection->handler_runner->continue_lock();
|
||||
if(!lock)
|
||||
|
|
@ -436,7 +438,7 @@ namespace SimpleWeb {
|
|||
// "After a successful async_read_until operation, the streambuf may contain additional data beyond the delimiter"
|
||||
// The chosen solution is to extract lines from the stream directly when parsing the header. What is left of the
|
||||
// streambuf (maybe some bytes of the content) is appended to in the async_read-function below (for retrieving content).
|
||||
size_t num_additional_bytes = session->request->streambuf.size() - bytes_transferred;
|
||||
std::size_t num_additional_bytes = session->request->streambuf.size() - bytes_transferred;
|
||||
|
||||
if(!RequestMessage::parse(session->request->content, session->request->method, session->request->path,
|
||||
session->request->query_string, session->request->http_version, session->request->header)) {
|
||||
|
|
@ -459,7 +461,7 @@ namespace SimpleWeb {
|
|||
}
|
||||
if(content_length > num_additional_bytes) {
|
||||
session->connection->set_timeout(config.timeout_content);
|
||||
asio::async_read(*session->connection->socket, session->request->streambuf, asio::transfer_exactly(content_length - num_additional_bytes), [this, session](const error_code &ec, size_t /*bytes_transferred*/) {
|
||||
asio::async_read(*session->connection->socket, session->request->streambuf, asio::transfer_exactly(content_length - num_additional_bytes), [this, session](const error_code &ec, std::size_t /*bytes_transferred*/) {
|
||||
session->connection->cancel_timeout();
|
||||
auto lock = session->connection->handler_runner->continue_lock();
|
||||
if(!lock)
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
#endif
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstddef>
|
||||
#include <openssl/ssl.h>
|
||||
|
||||
namespace SimpleWeb {
|
||||
|
|
@ -39,7 +40,7 @@ namespace SimpleWeb {
|
|||
session_id_context = std::to_string(config.port) + ':';
|
||||
session_id_context.append(config.address.rbegin(), config.address.rend());
|
||||
SSL_CTX_set_session_id_context(context.native_handle(), reinterpret_cast<const unsigned char *>(session_id_context.data()),
|
||||
std::min<size_t>(session_id_context.size(), SSL_MAX_SSL_SESSION_ID_LENGTH));
|
||||
std::min<std::size_t>(session_id_context.size(), SSL_MAX_SSL_SESSION_ID_LENGTH));
|
||||
}
|
||||
ServerBase::start();
|
||||
}
|
||||
|
|
|
|||
35
utility.hpp
35
utility.hpp
|
|
@ -7,6 +7,7 @@
|
|||
#include <memory>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <cstddef>
|
||||
|
||||
namespace SimpleWeb {
|
||||
inline bool case_insensitive_equal(const std::string &str1, const std::string &str2) noexcept {
|
||||
|
|
@ -24,8 +25,8 @@ namespace SimpleWeb {
|
|||
// Based on https://stackoverflow.com/questions/2590677/how-do-i-combine-hash-values-in-c0x/2595226#2595226
|
||||
class CaseInsensitiveHash {
|
||||
public:
|
||||
size_t operator()(const std::string &str) const noexcept {
|
||||
size_t h = 0;
|
||||
std::size_t operator()(const std::string &str) const noexcept {
|
||||
std::size_t h = 0;
|
||||
std::hash<int> hash;
|
||||
for(auto c : str)
|
||||
h ^= hash(tolower(c)) + 0x9e3779b9 + (h << 6) + (h >> 2);
|
||||
|
|
@ -62,7 +63,7 @@ namespace SimpleWeb {
|
|||
std::string result;
|
||||
result.reserve(value.size() / 3 + (value.size() % 3)); // Minimum size of result
|
||||
|
||||
for(size_t i = 0; i < value.size(); ++i) {
|
||||
for(std::size_t i = 0; i < value.size(); ++i) {
|
||||
auto &chr = value[i];
|
||||
if(chr == '%' && i + 2 < value.size()) {
|
||||
auto hex = value.substr(i + 1, 2);
|
||||
|
|
@ -103,10 +104,10 @@ namespace SimpleWeb {
|
|||
if(query_string.empty())
|
||||
return result;
|
||||
|
||||
size_t name_pos = 0;
|
||||
std::size_t name_pos = 0;
|
||||
auto name_end_pos = std::string::npos;
|
||||
auto value_pos = std::string::npos;
|
||||
for(size_t c = 0; c < query_string.size(); ++c) {
|
||||
for(std::size_t c = 0; c < query_string.size(); ++c) {
|
||||
if(query_string[c] == '&') {
|
||||
auto name = query_string.substr(name_pos, (name_end_pos == std::string::npos ? c : name_end_pos) - name_pos);
|
||||
if(!name.empty()) {
|
||||
|
|
@ -141,9 +142,9 @@ namespace SimpleWeb {
|
|||
CaseInsensitiveMultimap result;
|
||||
std::string line;
|
||||
getline(stream, line);
|
||||
size_t param_end;
|
||||
std::size_t param_end;
|
||||
while((param_end = line.find(':')) != std::string::npos) {
|
||||
size_t value_start = param_end + 1;
|
||||
std::size_t value_start = param_end + 1;
|
||||
if(value_start < line.size()) {
|
||||
if(line[value_start] == ' ')
|
||||
value_start++;
|
||||
|
|
@ -164,13 +165,13 @@ namespace SimpleWeb {
|
|||
header.clear();
|
||||
std::string line;
|
||||
getline(stream, line);
|
||||
size_t method_end;
|
||||
std::size_t method_end;
|
||||
if((method_end = line.find(' ')) != std::string::npos) {
|
||||
method = line.substr(0, method_end);
|
||||
|
||||
size_t query_start = std::string::npos;
|
||||
size_t path_and_query_string_end = std::string::npos;
|
||||
for(size_t i = method_end + 1; i < line.size(); ++i) {
|
||||
std::size_t query_start = std::string::npos;
|
||||
std::size_t path_and_query_string_end = std::string::npos;
|
||||
for(std::size_t i = method_end + 1; i < line.size(); ++i) {
|
||||
if(line[i] == '?' && (i + 1) < line.size())
|
||||
query_start = i + 1;
|
||||
else if(line[i] == ' ') {
|
||||
|
|
@ -186,7 +187,7 @@ namespace SimpleWeb {
|
|||
else
|
||||
path = line.substr(method_end + 1, path_and_query_string_end - method_end - 1);
|
||||
|
||||
size_t protocol_end;
|
||||
std::size_t protocol_end;
|
||||
if((protocol_end = line.find('/', path_and_query_string_end + 1)) != std::string::npos) {
|
||||
if(line.compare(path_and_query_string_end + 1, protocol_end - path_and_query_string_end - 1, "HTTP") != 0)
|
||||
return false;
|
||||
|
|
@ -213,7 +214,7 @@ namespace SimpleWeb {
|
|||
header.clear();
|
||||
std::string line;
|
||||
getline(stream, line);
|
||||
size_t version_end = line.find(' ');
|
||||
std::size_t version_end = line.find(' ');
|
||||
if(version_end != std::string::npos) {
|
||||
if(5 < line.size())
|
||||
version = line.substr(5, version_end - 5);
|
||||
|
|
@ -239,10 +240,10 @@ namespace SimpleWeb {
|
|||
static CaseInsensitiveMultimap parse(const std::string &line) {
|
||||
CaseInsensitiveMultimap result;
|
||||
|
||||
size_t para_start_pos = 0;
|
||||
size_t para_end_pos = std::string::npos;
|
||||
size_t value_start_pos = std::string::npos;
|
||||
for(size_t c = 0; c < line.size(); ++c) {
|
||||
std::size_t para_start_pos = 0;
|
||||
std::size_t para_end_pos = std::string::npos;
|
||||
std::size_t value_start_pos = std::string::npos;
|
||||
for(std::size_t c = 0; c < line.size(); ++c) {
|
||||
if(para_start_pos != std::string::npos) {
|
||||
if(para_end_pos == std::string::npos) {
|
||||
if(line[c] == ';') {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue