sprintf added, terminal colors

small code fixes and rearangements
This commit is contained in:
VaclavT 2021-03-09 22:57:16 +01:00
parent b4862ee196
commit 3f46ae9c94
10 changed files with 392 additions and 13 deletions

69
.vscode/settings.json vendored
View File

@ -1,3 +1,70 @@
{ {
"C_Cpp.default.configurationProvider": "ms-vscode.cmake-tools" "C_Cpp.default.configurationProvider": "ms-vscode.cmake-tools",
"files.associations": {
"__bit_reference": "cpp",
"__config": "cpp",
"__debug": "cpp",
"__errc": "cpp",
"__functional_base": "cpp",
"__hash_table": "cpp",
"__locale": "cpp",
"__mutex_base": "cpp",
"__node_handle": "cpp",
"__nullptr": "cpp",
"__split_buffer": "cpp",
"__string": "cpp",
"__threading_support": "cpp",
"__tree": "cpp",
"__tuple": "cpp",
"algorithm": "cpp",
"array": "cpp",
"atomic": "cpp",
"bitset": "cpp",
"cctype": "cpp",
"chrono": "cpp",
"cmath": "cpp",
"complex": "cpp",
"cstdarg": "cpp",
"cstddef": "cpp",
"cstdint": "cpp",
"cstdio": "cpp",
"cstdlib": "cpp",
"cstring": "cpp",
"ctime": "cpp",
"cwchar": "cpp",
"cwctype": "cpp",
"deque": "cpp",
"exception": "cpp",
"optional": "cpp",
"fstream": "cpp",
"functional": "cpp",
"initializer_list": "cpp",
"iomanip": "cpp",
"ios": "cpp",
"iosfwd": "cpp",
"iostream": "cpp",
"istream": "cpp",
"iterator": "cpp",
"limits": "cpp",
"locale": "cpp",
"map": "cpp",
"memory": "cpp",
"mutex": "cpp",
"new": "cpp",
"ostream": "cpp",
"ratio": "cpp",
"regex": "cpp",
"sstream": "cpp",
"stdexcept": "cpp",
"streambuf": "cpp",
"string": "cpp",
"string_view": "cpp",
"system_error": "cpp",
"tuple": "cpp",
"type_traits": "cpp",
"typeinfo": "cpp",
"unordered_map": "cpp",
"utility": "cpp",
"vector": "cpp"
}
} }

View File

@ -28,7 +28,8 @@ set(SOURCE
ml_string.cpp ml_string.cpp
clib/csvparser.cpp clib/csvparser.cpp
clib/sslclient.cpp clib/sslclient.cpp
clib/json11.cpp ml_date.h ml_date.cpp) clib/json11.cpp
clib/printf.cpp)
add_executable(${PROJECT_NAME} ${SOURCE}) add_executable(${PROJECT_NAME} ${SOURCE})

View File

@ -1,4 +1,6 @@
#pragma once
#include "../ml.h" #include "../ml.h"
#include <string> #include <string>

216
clib/printf.cpp Normal file
View File

@ -0,0 +1,216 @@
#include "printf.h"
#include <iomanip>
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
std::string mini_sprintf_format(bool left_align, bool sign, bool space_on_left, bool padding_by_zero, int width, int precision, int length, char specifier, const MlValue &value) {
std::string s;
bool is_positive = false;
if (specifier == 's') {
return value.as_string();
}
if (specifier == 'i' || specifier == 'd') {
int ival = value.as_int();
is_positive = ival >= 0;
s = std::to_string(ival);
} else if (specifier == 'f' || specifier == 'e') {
double dval = value.as_float();
is_positive = dval >= 0;
std::ostringstream stream_str;
if (specifier == 'f')
stream_str << std::fixed;
else
stream_str << std::scientific;
if (precision >= 0)
stream_str << std::setprecision(precision);
stream_str << dval;
s = stream_str.str(); // TODO ??
}
if (width > -1 && s.size() < width) {
int new_width = width - (sign && is_positive ? 1 : 0); // spce for + sign
if (s.size() < new_width) {
char padd = padding_by_zero ? '0' : ' ';
if (left_align) {
s.insert(0, new_width - s.size(), padd);
} else {
s.append(new_width - s.size(), ' '); // cannot append 0 because its different number then
}
}
}
if (sign && is_positive) {
s.insert(0, 1, '+');
}
if (space_on_left) {
s.insert(0, 1, ' ');
}
return s;
}
std::string mini_sprintf(const std::string &format_str, const std::vector<MlValue> &parameters) {
int arg_position = 0;
char c, c1;
std::string buf;
std::string output_str;
std::string::const_iterator si;
for (si = format_str.begin(); si != format_str.end(); ++si) {
c = *si;
// formating directives
if (c == '%') {
if (++si >= format_str.end()) {
return output_str; // end of string, invalid % on last pos
}
c1 = *si;
switch (c1) {
case '%':
output_str += c1;
break;
case '-':
case '+':
case ' ':
case '#':
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
case '.':
case 'i':
case 'd':
case 'f':
case 's':
bool left_align = false;
bool sign = false;
bool space_on_left = false;
bool padding_by_zero = false;
int width = -1;
int precision = -1;
int length = -1;
// http://www.cplusplus.com/reference/cstdio/printf/
// https://www.menie.org/georges/embedded/small_printf_source_code.html
//
// %[flags][width][.precision][length]specifier
// flags: - + \_ # 0
while ((*si == '-' || *si == '+' || *si == ' ' || *si == '#' || *si == '0') && si < format_str.end()) {
switch (*si) {
case '-':
left_align = true;
break;
case '+':
sign = true;
break;
case ' ':
space_on_left = true;
break;
case '#':
break;
case '0':
padding_by_zero = true;
left_align = true;
break;
};
si++;
}
// width
if (si >= format_str.end())
return output_str; // invalid end of string
while (*si >= '0' && *si <= '9' && si < format_str.end()) {
if (width == -1) {
width = 0;
}
width = width * 10 + (*si - '0');
si++;
}
// precision
if (si >= format_str.end())
return output_str; // invalid end of string
if (*si == '.') {
precision = 0;
if (++si >= format_str.end())
return output_str; // invalid end of string
while (*si >= '0' && *si <= '9' && si < format_str.end()) {
precision = precision * 10 + (*si - '0');
si++;
}
}
// length
// specifier
if (si >= format_str.end())
return output_str; // invalid end of string
if (*si == 'i' || *si == 'd' || *si == 'f' || *si == 's') { // TODO more specifiers
std::string s = mini_sprintf_format(left_align, sign, space_on_left, padding_by_zero, width, precision, length, *si, parameters[arg_position]);
arg_position++;
output_str += s;
} else {
output_str += "UNKNOWN FORMAT SPECIFIER";
}
};
// escaping sequences
} else if (c == '\\') {
if (++si >= format_str.end()) {
return output_str; // end of string, invalid % on last pos
}
c1 = *si;
switch (c1) {
case 't':
output_str += '\t';
break;
case 'r':
output_str += '\r';
break;
case 'n':
output_str += '\n';
break;
case 'x': // hex ie \x1b
if (si + 2 >= format_str.end()) return output_str; // end of string, invalid hex constant
buf.clear();
buf.push_back(*(si + 1));
buf.push_back(*(si + 2));
output_str.push_back((char)std::strtol( &buf[0], 0, 16));
si += 2;
break;
case '0': // octal ie "\033"
if (si + 2 >= format_str.end()) return output_str; // end of string, invalid octal constant
buf.clear();
buf.push_back(*(si + 1));
buf.push_back(*(si + 2));
output_str.push_back((char)std::strtol( &buf[0], 0, 8));
// TODO maybe octal constant has 3 bytes
// if (si + 2 >= format_str.end()) return output_str; // end of string, invalid octal or hex constant
// buf.push_back(*(si + 3));
// si += 3;
si += 2;
break;
default:
output_str += c1;
};
// normal characters
} else {
output_str += c;
}
}
return output_str;
}

12
clib/printf.h Normal file
View File

@ -0,0 +1,12 @@
#pragma once
#include "../ml.h"
#include <iomanip>
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
std::string mini_sprintf(const std::string &format_str, const std::vector<MlValue> &parameters);

View File

@ -1,3 +1,4 @@
#pragma once
#include <openssl/err.h> #include <openssl/err.h>
#include <openssl/ssl.h> #include <openssl/ssl.h>

View File

@ -1,3 +1,35 @@
(define json_list (parse-json "{\"k1\":\"v1\", \"k2\":42, \"k3\":[\"a\",123,true,false,null]}"))
(print json_list) ; (print (sprintf "\033[31mred text"))
(for x json_list (print x)) ; (print (sprintf "\x1B[31mred text"))
(define term-rst-esc "\x1B[0m")
(define term-red-esc '"\x1B[31m")
(define term-green-esc "\x1B[32m")
(define term-yellow-esc "\x1B[33m")
(define term-blue-esc "\x1B[34m")
(define term-magenta-esc "\x1B[35m")
(define term-cyan-esc "\x1B[36m")
(define term-white-esc "\x1B[37m")
(define term-bold-esc "\x1B[1m")
(define term-underline-esc "\x1B[4m")
(defun term-red (str) (sprintf (+ term-red-esc str term-rst-esc)))
(defun term-green (str) (sprintf (+ term-green-esc str term-rst-esc)))
(defun term-yellow (str) (sprintf (+ term-yellow-esc str term-rst-esc)))
(defun term-blue (str) (sprintf (+ term-blue-esc str term-rst-esc)))
(defun term-magenta (str) (sprintf (+ term-magenta-esc str term-rst-esc)))
(defun term-cyan (str) (sprintf (+ term-cyan-esc str term-rst-esc)))
(defun term-white (str) (sprintf (+ term-white-esc str term-rst-esc)))
(defun term-bold (str) (sprintf (+ term-bold-esc str term-rst-esc)))
(defun term-underline (str) (sprintf (+ term-underline-esc str term-rst-esc)))
(print (term-red "red text"))
(print (term-green "green text"))
(print (term-yellow "yellow text"))
(print (term-blue "blue text"))
(print (term-magenta "magenta text"))
(print (term-cyan "cyan text"))
(print (term-white "white text"))
(print (term-bold "bold text"))
(print (term-underline "underline text"))
(print "normal text")

26
ml.cpp
View File

@ -7,6 +7,7 @@
#include "clib/csvparser.h" #include "clib/csvparser.h"
#include "clib/sslclient.h" #include "clib/sslclient.h"
#include "clib/json11.h" #include "clib/json11.h"
#include "clib/printf.h"
#include <cmath> #include <cmath>
@ -176,7 +177,7 @@ int MlValue::as_int() const {
// Get this item's floating point value // Get this item's floating point value
double MlValue::as_float() const { double MlValue::as_float() const {
return cast_to_int().stack_data.f; return cast_to_float().stack_data.f;
} }
// Get this item's string value // Get this item's string value
@ -728,7 +729,7 @@ MlValue parse(std::string &s, int &ptr) {
skip_whitespace(s, ptr); skip_whitespace(s, ptr);
if (s[ptr] == ';') if (s[ptr] == ';')
throw std::runtime_error("this should never happen!"); throw std::runtime_error(INTERNAL_ERROR);
if (s == "") { if (s == "") {
@ -1084,8 +1085,7 @@ namespace builtin {
// TODO add support for more params specifying options // TODO add support for more params specifying options
if (args.size() != 1) if (args.size() != 1)
throw MlError(MlValue("parse-json", parse_json), env, throw MlError(MlValue("parse-json", parse_json), env, args.size() > 1 ? TOO_MANY_ARGS : TOO_FEW_ARGS);
args.size() > 1 ? TOO_MANY_ARGS : TOO_FEW_ARGS);
std::string str = args[0].as_string(); std::string str = args[0].as_string();
std::string err; std::string err;
@ -1099,7 +1099,7 @@ namespace builtin {
return json.ivalualize(); return json.ivalualize();
} }
// get current time as secs from epoch // Get current time as secs from epoch
MlValue get_universal_time(std::vector<MlValue> args, MlEnvironment &env) { MlValue get_universal_time(std::vector<MlValue> args, MlEnvironment &env) {
eval_args(args, env); eval_args(args, env);
@ -1113,8 +1113,7 @@ namespace builtin {
eval_args(args, env); eval_args(args, env);
if (args.size() != 2) if (args.size() != 2)
throw MlError(MlValue("date_to_str", date_to_str), env, throw MlError(MlValue("date_to_str", date_to_str), env, args.size() > 2 ? TOO_MANY_ARGS : TOO_FEW_ARGS);
args.size() > 2 ? TOO_MANY_ARGS : TOO_FEW_ARGS);
return MlValue::string(date_to_string(args[0].as_int(), args[1].as_string())); return MlValue::string(date_to_string(args[0].as_int(), args[1].as_string()));
} }
@ -1498,7 +1497,7 @@ namespace builtin {
eval_args(args, env); eval_args(args, env);
if (args.size() != 4) if (args.size() != 4)
throw MlError(MlValue("regex_search", regex_search), env, args.size() > 4 ? TOO_MANY_ARGS : TOO_FEW_ARGS); throw MlError(MlValue("string_pad", string_pad), env, args.size() > 4 ? TOO_MANY_ARGS : TOO_FEW_ARGS);
// TODO validate len > 0 etc // TODO validate len > 0 etc
return MlValue::string(string_padd(args[0].as_string(), args[1].as_int(), args[2].as_string()[0], (args[3].as_string()=="rpad"))); return MlValue::string(string_padd(args[0].as_string(), args[1].as_int(), args[2].as_string()[0], (args[3].as_string()=="rpad")));
@ -1522,6 +1521,16 @@ namespace builtin {
return MlValue::string(args[0].debug()); return MlValue::string(args[0].debug());
} }
MlValue sprintf(std::vector<MlValue> args, MlEnvironment &env) {
eval_args(args, env);
std::string result;
if (args.size() < 1 || args.size() > 2)
throw MlError(MlValue("sprintf", sprintf), env, args.size() > 2 ? TOO_MANY_ARGS : TOO_FEW_ARGS);
return MlValue::string(mini_sprintf(args[0].as_string(), args.size()==2 ? args[1].as_list() : std::vector<MlValue> {} ));
}
// >>> (map (lambda (x) (+ x 10)) '(1 2 3 4 5 6)) // >>> (map (lambda (x) (+ x 10)) '(1 2 3 4 5 6))
// => (11 12 13 14 15 16) // => (11 12 13 14 15 16)
MlValue map_list(std::vector<MlValue> args, MlEnvironment &env) { MlValue map_list(std::vector<MlValue> args, MlEnvironment &env) {
@ -1741,6 +1750,7 @@ MlValue MlEnvironment::get(const std::string &name) const {
// String operations // String operations
if (name == "debug") return MlValue("debug", builtin::debug); if (name == "debug") return MlValue("debug", builtin::debug);
if (name == "sprintf") return MlValue("sprintf", builtin::sprintf);
if (name == "display") return MlValue("display", builtin::display); if (name == "display") return MlValue("display", builtin::display);
if (name == "replace") return MlValue("replace", builtin::replace); if (name == "replace") return MlValue("replace", builtin::replace);
if (name == "regex-search?") return MlValue("regex-search?", builtin::regex_search); if (name == "regex-search?") return MlValue("regex-search?", builtin::regex_search);

22
stdlib/terminal.lsp Normal file
View File

@ -0,0 +1,22 @@
(define term-rst-esc "\x1B[0m")
(define term-red-esc '"\x1B[31m")
(define term-green-esc "\x1B[32m")
(define term-yellow-esc "\x1B[33m")
(define term-blue-esc "\x1B[34m")
(define term-magenta-esc "\x1B[35m")
(define term-cyan-esc "\x1B[36m")
(define term-white-esc "\x1B[37m")
(define term-bold-esc "\x1B[1m")
(define term-underline-esc "\x1B[4m")
(defun term-red (str) (sprintf (+ term-red-esc str term-rst-esc)))
(defun term-green (str) (sprintf (+ term-green-esc str term-rst-esc)))
(defun term-yellow (str) (sprintf (+ term-yellow-esc str term-rst-esc)))
(defun term-blue (str) (sprintf (+ term-blue-esc str term-rst-esc)))
(defun term-magenta (str) (sprintf (+ term-magenta-esc str term-rst-esc)))
(defun term-cyan (str) (sprintf (+ term-cyan-esc str term-rst-esc)))
(defun term-white (str) (sprintf (+ term-white-esc str term-rst-esc)))
(defun term-bold (str) (sprintf (+ term-bold-esc str term-rst-esc)))
(defun term-underline (str) (sprintf (+ term-underline-esc str term-rst-esc)))

View File

@ -158,4 +158,20 @@
(print "list:" l) (print "list:" l)
(print "flatten-ed list:" (flatten l)) (print "flatten-ed list:" (flatten l))
(print (sprintf "%.2f" '(1.23456)))
(print (sprintf "%d" '(10000000)))
(print (term-red "red text"))
(print (term-green "green text"))
(print (term-yellow "yellow text"))
(print (term-blue "blue text"))
(print (term-magenta "magenta text"))
(print (term-cyan "cyan text"))
(print (term-white "white text"))
(print (term-bold "bold text"))
(print (term-underline "underline text"))
(print "normal text")
(print "Test ends") (print "Test ends")