builtin: str.last_index(); pref: hide-auto-str;

This commit is contained in:
Alexander Medvednikov 2024-03-28 18:26:30 +03:00
parent 85533fe178
commit acf0107493
13 changed files with 82 additions and 49 deletions

View file

@ -118,7 +118,6 @@ fn main() {
bg_color: gx.white bg_color: gx.white
width: win_width width: win_width
height: win_height height: win_height
use_ortho: true
create_window: true create_window: true
window_title: 'Quadtree Demo' window_title: 'Quadtree Demo'
frame_fn: frame frame_fn: frame

View file

@ -269,6 +269,9 @@ pub fn println(s string) {
println('println(NIL)') println('println(NIL)')
return return
} }
$if noprintln ? {
return
}
$if android && !termux { $if android && !termux {
C.android_print(C.stdout, c'%.*s\n', s.len, s.str) C.android_print(C.stdout, c'%.*s\n', s.len, s.str)
return return

View file

@ -750,7 +750,14 @@ fn (s string) index_last_(p string) int {
} }
// index_last returns the position of the first character of the *last* occurrence of the `needle` string in `s`. // index_last returns the position of the first character of the *last* occurrence of the `needle` string in `s`.
@[deprecated: 'use `.last_index(needle string)` instead']
pub fn (s string) index_last(needle string) ?int { pub fn (s string) index_last(needle string) ?int {
return s.last_index(needle)
}
// last_index returns the position of the first character of the *last* occurrence of the `needle` string in `s`.
@[inline]
pub fn (s string) last_index(needle string) ?int {
idx := s.index_last_(needle) idx := s.index_last_(needle)
if idx == -1 { if idx == -1 {
return none return none
@ -758,14 +765,6 @@ pub fn (s string) index_last(needle string) ?int {
return idx return idx
} }
// last_index returns the position of the first character of the *last* occurrence of the `needle` string in `s`.
@[deprecated: 'use `.index_last(needle string)` instead']
@[deprecated_after: '2023-12-18']
@[inline]
pub fn (s string) last_index(needle string) ?int {
return s.index_last(needle)
}
pub fn (s string) trim_space() string { pub fn (s string) trim_space() string {
res := '' res := ''
#res.str = s.str.trim() #res.str = s.str.trim()

View file

@ -1090,7 +1090,7 @@ pub fn (s string) substr(start int, _end int) string {
end := if _end == max_int { s.len } else { _end } // max_int end := if _end == max_int { s.len } else { _end } // max_int
$if !no_bounds_checking { $if !no_bounds_checking {
if start > end || start > s.len || end > s.len || start < 0 || end < 0 { if start > end || start > s.len || end > s.len || start < 0 || end < 0 {
panic('substr(${start}, ${end}) out of bounds (len=${s.len})') panic('substr(${start}, ${end}) out of bounds (len=${s.len}) s="${s}"')
} }
} }
len := end - start len := end - start
@ -1223,7 +1223,15 @@ pub fn (s string) index(p string) ?int {
} }
// index_last returns the position of the first character of the *last* occurrence of the `needle` string in `s`. // index_last returns the position of the first character of the *last* occurrence of the `needle` string in `s`.
@[deprecated: 'use `.last_index(needle string)` instead']
@[deprecated_after: '2024-03-27']
pub fn (s string) index_last(needle string) ?int { pub fn (s string) index_last(needle string) ?int {
return s.last_index(needle)
}
// last_index returns the position of the first character of the *last* occurrence of the `needle` string in `s`.
@[inline]
pub fn (s string) last_index(needle string) ?int {
idx := s.index_last_(needle) idx := s.index_last_(needle)
if idx == -1 { if idx == -1 {
return none return none
@ -1231,14 +1239,6 @@ pub fn (s string) index_last(needle string) ?int {
return idx return idx
} }
// last_index returns the position of the first character of the *last* occurrence of the `needle` string in `s`.
@[deprecated: 'use `.index_last(needle string)` instead']
@[deprecated_after: '2023-12-18']
@[inline]
pub fn (s string) last_index(needle string) ?int {
return s.index_last(needle)
}
// index_kmp does KMP search. // index_kmp does KMP search.
@[direct_array_access; manualfree] @[direct_array_access; manualfree]
fn (s string) index_kmp(p string) int { fn (s string) index_kmp(p string) int {

View file

@ -54,6 +54,7 @@ pub fn (ctx &Context) draw_line(x f32, y f32, x2 f32, y2 f32, c gx.Color) {
$if macos { $if macos {
if ctx.native_rendering { if ctx.native_rendering {
// Make the line more clear on hi dpi screens: draw a rectangle // Make the line more clear on hi dpi screens: draw a rectangle
// TODO this is broken if the line's x1 != x2
mut width := math.abs(x2 - x) mut width := math.abs(x2 - x)
mut height := math.abs(y2 - y) mut height := math.abs(y2 - y)
if width == 0 { if width == 0 {

View file

@ -291,9 +291,9 @@ pub fn (ctx &Context) draw_image_with_config(config DrawImageConfig) {
if config.img_id > 0 { if config.img_id > 0 {
img = &ctx.image_cache[config.img_id] img = &ctx.image_cache[config.img_id]
} else { } else {
//$if !noggverbose ? { $if !noggverbose ? {
eprintln('gg: failed to get image to draw natively') eprintln('gg: failed to get image to draw natively')
//} }
return return
} }
} }
@ -301,31 +301,33 @@ pub fn (ctx &Context) draw_image_with_config(config DrawImageConfig) {
eprintln('gg: draw_image() bad img id ${img.id} (img cache len = ${ctx.image_cache.len})') eprintln('gg: draw_image() bad img id ${img.id} (img cache len = ${ctx.image_cache.len})')
return return
} }
if ctx.native_rendering { if img.width == 0 {
if img.width == 0 { println('w=0')
println('w=0')
return
}
if !os.exists(img.path) {
println('not exist path')
return
}
x := config.img_rect.x
y := config.img_rect.y
width := if config.img_rect.width == 0 {
f32(img.width)
} else {
config.img_rect.width
}
height := if config.img_rect.height == 0 {
f32(img.height)
} else {
config.img_rect.height
}
C.darwin_draw_image(x, ctx.height - (y + config.img_rect.height),
width, height, img)
return return
} }
if !os.exists(img.path) {
println('not exist path')
return
}
x := config.img_rect.x
y := config.img_rect.y
width := if config.img_rect.width == 0 {
// Calculate the width by dividing it by the height ratio.
// e.g. the original image is 100x100, we're drawing 0x20. Find the ratio (5)
// by dividing the height 100 by 20, and then divide the width by 5.
f32(img.width / (img.height / config.img_rect.height))
} else {
config.img_rect.width
}
height := if config.img_rect.height == 0 {
// Same as above.
f32(img.height / (img.width / config.img_rect.width))
} else {
config.img_rect.height
}
C.darwin_draw_image(x, ctx.height - (y + config.img_rect.height), width,
height, img)
return
} }
} }
} }

View file

@ -186,6 +186,7 @@ pub fn (ctx &Context) draw_text(x int, y int, text_ string, cfg gx.TextCfg) {
if ctx.native_rendering { if ctx.native_rendering {
if cfg.align == gx.align_right { if cfg.align == gx.align_right {
width := ctx.text_width(text_) width := ctx.text_width(text_)
// println('draw text ctx.height = ${ctx.height}')
C.darwin_draw_string(x - width, ctx.height - y, text_, cfg) C.darwin_draw_string(x - width, ctx.height - y, text_, cfg)
} else { } else {
C.darwin_draw_string(x, ctx.height - y, text_, cfg) C.darwin_draw_string(x, ctx.height - y, text_, cfg)

View file

@ -25,3 +25,17 @@ pub fn download_file(url string, out_file_path string) ! {
// type DownloadChunkFn = fn (written int) // type DownloadChunkFn = fn (written int)
// type DownloadFinishedFn = fn () // type DownloadFinishedFn = fn ()
// pub fn download_file_with_progress(url string, out_file_path string, cb_chunk DownloadChunkFn, cb_finished DownloadFinishedFn) // pub fn download_file_with_progress(url string, out_file_path string, cb_chunk DownloadChunkFn, cb_finished DownloadFinishedFn)
pub fn download_file_with_cookies(url string, out_file_path string, cookies map[string]string) ! {
$if debug_http ? {
println('http.download_file url=${url} out_file_path=${out_file_path}')
}
s := fetch(method: .get, url: url, cookies: cookies) or { return err }
if s.status() != .ok {
return error('received http code ${s.status_code}')
}
$if debug_http ? {
println('http.download_file saving ${s.body.len} bytes')
}
os.write_file(out_file_path, s.body)!
}

View file

@ -81,17 +81,22 @@ foo := Foo{
] ]
} }
sql db { foo_id := sql db {
insert foo into Foo insert foo into Foo
}! }!
``` ```
If the `id` field is marked as `serial` and `primary`, the insert expression
returns the database ID of the newly added object. Getting an ID of a newly
added DB row is often useful.
When inserting, `[sql: serial]` fields, and fields with a `[default: 'raw_sql']` When inserting, `[sql: serial]` fields, and fields with a `[default: 'raw_sql']`
attribute are not sent to the database when the value being sent is the default attribute are not sent to the database when the value being sent is the default
for the V struct field (e.g., 0 int, or an empty string). This allows the for the V struct field (e.g., 0 int, or an empty string). This allows the
database to insert default values for auto-increment fields and where you have database to insert default values for auto-increment fields and where you have
specified a default. specified a default.
### Update ### Update
```v ignore ```v ignore

View file

@ -274,7 +274,7 @@ pub fn dir(opath string) string {
} }
other_separator := if path_separator == '/' { '\\' } else { '/' } other_separator := if path_separator == '/' { '\\' } else { '/' }
path := opath.replace(other_separator, path_separator) path := opath.replace(other_separator, path_separator)
pos := path.index_last(path_separator) or { return '.' } pos := path.last_index(path_separator) or { return '.' }
if pos == 0 && path_separator == '/' { if pos == 0 && path_separator == '/' {
return '/' return '/'
} }
@ -296,10 +296,10 @@ pub fn base(opath string) string {
} }
if path.ends_with(path_separator) { if path.ends_with(path_separator) {
path2 := path[..path.len - 1] path2 := path[..path.len - 1]
pos := path2.index_last(path_separator) or { return path2.clone() } pos := path2.last_index(path_separator) or { return path2.clone() }
return path2[pos + 1..] return path2[pos + 1..]
} }
pos := path.index_last(path_separator) or { return path.clone() } pos := path.last_index(path_separator) or { return path.clone() }
return path[pos + 1..] return path[pos + 1..]
} }

View file

@ -484,7 +484,7 @@ fn (mut c Checker) check_valid_snake_case(name string, identifier string, pos to
} }
fn stripped_name(name string) string { fn stripped_name(name string) string {
idx := name.index_last('.') or { -1 } idx := name.last_index('.') or { -1 }
return name[(idx + 1)..] return name[(idx + 1)..]
} }

View file

@ -928,6 +928,11 @@ fn (mut g Gen) gen_str_for_struct(info ast.Struct, lang ast.Language, styp strin
} }
} }
} }
// -hide-auto-str hides potential sensitive struct data from resulting binary files
if g.pref.hide_auto_str {
fn_body.writeln('\tstring res = { .str ="str() used with -hide-auto-str", .len=30 }; return res;')
return
}
fn_body.writeln('\tstring res = str_intp( ${(info.fields.len - field_skips.len) * 4 + 3}, _MOV((StrIntpData[]){') fn_body.writeln('\tstring res = str_intp( ${(info.fields.len - field_skips.len) * 4 + 3}, _MOV((StrIntpData[]){')
fn_body.writeln('\t\t{_SLIT("${clean_struct_v_type_name}{\\n"), 0, {.d_c=0}},') fn_body.writeln('\t\t{_SLIT("${clean_struct_v_type_name}{\\n"), 0, {.d_c=0}},')

View file

@ -141,6 +141,7 @@ pub mut:
profile_fns []string // when set, profiling will be off by default, but inside these functions (and what they call) it will be on. profile_fns []string // when set, profiling will be off by default, but inside these functions (and what they call) it will be on.
translated bool // `v translate doom.v` are we running V code translated from C? allow globals, ++ expressions, etc translated bool // `v translate doom.v` are we running V code translated from C? allow globals, ++ expressions, etc
obfuscate bool // `v -obf program.v`, renames functions to "f_XXX" obfuscate bool // `v -obf program.v`, renames functions to "f_XXX"
hide_auto_str bool // `v -hide-auto-str program.v`, doesn't generate str() with struct data
// Note: passing -cg instead of -g will set is_vlines to false and is_debug to true, thus making v generate cleaner C files, // Note: passing -cg instead of -g will set is_vlines to false and is_debug to true, thus making v generate cleaner C files,
// which are sometimes easier to debug / inspect manually than the .tmp.c files by plain -g (when/if v line number generation breaks). // which are sometimes easier to debug / inspect manually than the .tmp.c files by plain -g (when/if v line number generation breaks).
sanitize bool // use Clang's new "-fsanitize" option sanitize bool // use Clang's new "-fsanitize" option
@ -642,6 +643,9 @@ pub fn parse_args_and_show_errors(known_external_commands []string, args []strin
'-obf', '-obfuscate' { '-obf', '-obfuscate' {
res.obfuscate = true res.obfuscate = true
} }
'-hide-auto-str' {
res.hide_auto_str = true
}
'-translated' { '-translated' {
res.translated = true res.translated = true
res.gc_mode = .no_gc // no gc in c2v'ed code, at least for now res.gc_mode = .no_gc // no gc in c2v'ed code, at least for now