From 8a89e71f13f692ec4a5bbd6f7d263fcebb22152d Mon Sep 17 00:00:00 2001 From: Steffen Winterfeldt Date: Wed, 30 Nov 2005 14:25:58 +0000 Subject: - adjust to syslinux 3.11 - remove some primary words and reimplement them as bytecode - read config options from 'gfxboot.cfg' --- Changelog | 2 +- bincode.asm | 579 ++++++++++++++++++++++++++++++---------------- mk_vocabulary | 6 +- themes/SuSE/common.inc | 31 +-- themes/SuSE/dia_video.inc | 95 ++++---- themes/SuSE/system.inc | 54 +++++ 6 files changed, 494 insertions(+), 273 deletions(-) diff --git a/Changelog b/Changelog index 24e9844..4e6b8c5 100644 --- a/Changelog +++ b/Changelog @@ -1,4 +1,4 @@ -25/11/2005: v3.2.4 +30/11/2005: v3.2.4 - adjust to syslinux 3.11 - remove some primary words and reimplement them as bytecode - read config options from 'gfxboot.cfg' diff --git a/bincode.asm b/bincode.asm index 20c9e44..c92ff97 100644 --- a/bincode.asm +++ b/bincode.asm @@ -156,7 +156,7 @@ malloc.end dd 0 malloc.area times malloc.areas * 2 dd 0 vbe_buffer dd 0 ; (seg:ofs) buffer for vbe calls -vbe_mode_list dd 0 ; (seg:ofs) list with vbe modes +vbe_mode_list dd 0 ; (seg:ofs) list with (up to 100h) vbe modes infobox_buffer dd 0 ; (lin) temp buffer for InfoBox messages local_stack dd 0 ; (seg:ofs) local stack (8k) @@ -762,6 +762,8 @@ gfx_init_40: push eax call lin2so pop dword [vbe_mode_list] + ; fill list + call get_vbe_modes ; get console font call cfont_init @@ -2897,8 +2899,6 @@ set_mode_20: pop di cmp ax,4fh jnz set_mode_80 - push word [es:di+12h] - pop word [screen_mem] mov ax,4f01h mov cx,[gfx_mode] push di @@ -3047,29 +3047,20 @@ mode_init_90: ; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ; -; Find graphics mode. +; Get VBE mode list. ; -; edx width -; ecx height -; eax color bits ; [vbe_buffer] buffer for vbe info ; ; return: -; eax mode number -; CF 1 = not found +; [vbe_mode_list] mode list, last entry is 0xffff +; [screen_mem] video memory size ; -find_mode: +get_vbe_modes: push es - mov [tmp_write_data],dx - mov [tmp_write_data+2],cx - mov [tmp_write_data+4],ax - lfs si,[vbe_mode_list] cmp word [fs:si],0 - jnz find_mode_40 - - ; ok, get list first + jnz get_vbe_modes_90 les di,[vbe_buffer] mov ax,4f00h @@ -3078,79 +3069,32 @@ find_mode: int 10h pop di cmp ax,4fh - jnz find_mode_30 + jnz get_vbe_modes_30 + push word [es:di+12h] + pop word [screen_mem] lfs si,[es:di+0eh] les di,[vbe_mode_list] mov cx,0ffh -find_mode_10: +get_vbe_modes_10: fs lodsw stosw cmp ax,0ffffh - jz find_mode_20 + jz get_vbe_modes_20 dec cx - jnz find_mode_10 + jnz get_vbe_modes_10 mov word [es:di],0ffffh -find_mode_20: +get_vbe_modes_20: lfs si,[vbe_mode_list] cmp word [fs:si],0 - jnz find_mode_40 + jnz get_vbe_modes_90 ; make sure it's not 0; mode 1 is the same as mode 0 mov byte [fs:si],1 - jmp find_mode_40 -find_mode_30: + jmp get_vbe_modes_90 +get_vbe_modes_30: lfs si,[vbe_mode_list] mov word [fs:si],0ffffh -find_mode_40: - fs lodsw - cmp ax,0ffffh - jz find_mode_80 - xchg ax,cx - les di,[vbe_buffer] - mov ax,4f01h - push fs - push si - push di - push cx - int 10h - pop cx - pop di - pop si - pop fs - cmp ax,4fh - jnz find_mode_40 - - test byte [es:di],1 ; mode supported? - jz find_mode_40 - - mov eax,[es:di+12h] ; size - cmp eax,[tmp_write_data] - jnz find_mode_40 - - mov dl,[es:di+1bh] ; color mode (aka memory model) - mov dh,[es:di+19h] ; color depth - cmp dl,6 ; direct color - jnz find_mode_60 - cmp dh,32 - jz find_mode_70 - mov dh,[es:di+1fh] ; red - add dh,[es:di+21h] ; green - add dh,[es:di+23h] ; blue - jmp find_mode_70 -find_mode_60: - cmp dl,4 ; PL8 - jnz find_mode_40 - mov dh,8 -find_mode_70: - cmp dh,[tmp_write_data+4] - jnz find_mode_40 - - movzx eax,cx - jmp find_mode_90 - -find_mode_80: - stc -find_mode_90: +get_vbe_modes_90: pop es ret @@ -3775,7 +3719,7 @@ ps_status_info: mov si,msg_13 call printf - mov cx,4 + mov cx,7 ps_status_info_10: push cx @@ -6624,6 +6568,42 @@ prim_vscreensize_90: ret +;; monitorsize - monitor size +; +; group: gfx.screen +; +; ( -- int1 int2 ) +; +; int1, int2: width and height +; +prim_monitorsize: + mov ax,[pstack_ptr] + inc ax + inc ax + cmp [pstack_size],ax + mov bp,pserr_pstack_overflow + jb prim_monitorsize_90 + mov [pstack_ptr],ax + + cmp word [ddc_xtimings],0 + jnz prim_monitorsize_50 + + call get_monitor_res + +prim_monitorsize_50: + + mov dl,t_int + movzx eax,word [ddc_xtimings] + mov cx,1 + call set_pstack_tos + mov dl,t_int + movzx eax,word [ddc_xtimings + 2] + xor cx,cx + call set_pstack_tos +prim_monitorsize_90: + ret + + ;; image.size - graphics image size ; ; group: image @@ -8391,61 +8371,159 @@ prim_currentmode: jmp pr_getint -;; findmode - find video mode number +;; videomodes - video mode list length ; ; group: gfx.screen ; -; ( int1 int2 int3 -- int4 ) +; ( -- int1 ) ; -; int1, int2: width, height -; int3: color bits -; int4: mode number +; int1: video mode list length (always >= 1) +; +prim_videomodes: + lfs si,[vbe_mode_list] + xor eax,eax + +prim_videomodes_20: + add si,2 + inc ax + cmp word [fs:si-2],0xffff + jnz prim_videomodes_20 + + jmp pr_getint + + +;; videomodeinfo - return video mode info +; +; group: gfx.screen +; +; ( int1 -- int2 int3 int4 int5 ) +; +; int1: mode index +; int2, int3: width, height +; int4: color bits +; int5: mode number (bit 14: framebuffer mode) or .undef ; ; example -; 1024 768 16 findmode setmode % 1024x768, 16-bit color mode +; 2 videomodeinfo ; -prim_findmode: - mov bp,pserr_pstack_underflow - cmp word [pstack_ptr],byte 3 - jc prim_findmode_90 +prim_videomodeinfo: + mov dl,t_int + call get_1arg + jc prim_vmi_90 - mov bp,pserr_wrong_arg_types - mov cx,2 - call get_pstack_tos - cmp dl,t_int - stc - jnz prim_findmode_90 - push eax - mov dx,t_int + (t_int << 8) - call get_2args - pop edx - jc prim_findmode_90 + mov cx,[pstack_ptr] + add cx,3 + cmp [pstack_size],cx + mov bp,pserr_pstack_overflow + jb prim_vmi_90 + mov [pstack_ptr],cx - ; eax: color - ; ecx: height - ; edx: width + cmp eax,100h + jb prim_vmi_10 + mov ax,0ffh +prim_vmi_10: + add ax,ax + lfs si,[vbe_mode_list] + add si,ax + mov cx,[fs:si] + or cx,cx + jz prim_vmi_60 + cmp cx,-1 + jz prim_vmi_60 - call find_mode - jnc prim_findmode_50 + push es - mov dl,t_none - xor eax,eax + les di,[vbe_buffer] + mov ax,4f01h + push di + push cx + int 10h + pop cx + pop di - jmp prim_findmode_60 + pop es + mov fs,[vbe_buffer+2] -prim_findmode_50: + cmp ax,4fh + jnz prim_vmi_60 + + test byte [fs:di],1 ; mode supported? + jz prim_vmi_60 + + movzx eax,cx + and ax,~(1 << 14) + cmp dword [fs:di+28h],byte 0 ; framebuffer start + jz prim_vmi_20 + or ax,1 << 14 +prim_vmi_20: mov dl,t_int + xor cx,cx + push di + call set_pstack_tos + pop di -prim_findmode_60: - sub word [pstack_ptr],byte 2 + movzx eax,word [fs:di+12h] ; width + mov dl,t_int + mov cx,3 + push di + call set_pstack_tos + pop di + + movzx eax,word [fs:di+14h] ; heigth + mov dl,t_int + mov cx,2 + push di + call set_pstack_tos + pop di + mov dl,[fs:di+1bh] ; color mode (aka memory model) + mov dh,[fs:di+19h] ; color depth + + cmp dl,6 ; direct color + jnz prim_vmi_30 + cmp dh,32 + jz prim_vmi_40 + mov dh,[fs:di+1fh] ; red + add dh,[fs:di+21h] ; green + add dh,[fs:di+23h] ; blue + jmp prim_vmi_40 +prim_vmi_30: + cmp dl,4 ; PL8 + jnz prim_vmi_60 + mov dh,8 +prim_vmi_40: + movzx eax,dh + + mov dl,t_int + mov cx,1 + call set_pstack_tos + + jmp prim_vmi_90 + +prim_vmi_60: + ; no mode + xor eax,eax + mov dl,t_int + mov cx,3 + call set_pstack_tos + xor eax,eax + mov dl,t_int + mov cx,2 + call set_pstack_tos + xor eax,eax + mov dl,t_int + mov cx,1 + call set_pstack_tos + xor eax,eax + mov dl,t_none xor cx,cx call set_pstack_tos -prim_findmode_90: +prim_vmi_90: ret + ;; colorbits - current pixel size ; ; group: gfx.screen @@ -9284,100 +9362,6 @@ prim_currenttitle: jmp pr_getobj -;; videomodes - return number of boot loader video modes -; -; group: system -; -; ( -- int1 ) -; -; int1: number of video modes the boot loader suggest for kernel -; (syslinux/isolinux only). -; -prim_videomodes: - mov ax,[pstack_ptr] - inc ax - cmp [pstack_size],ax - mov bp,pserr_pstack_overflow - jb prim_videomodes_90 - mov [pstack_ptr],ax - - mov es,[boot_cs] - mov si,[boot_sysconfig] - movzx cx,byte [es:si+4] - mov si,[es:si+2] - xor eax,eax - or cx,cx - jz prim_videomodes_40 -prim_videomodes_20: - cmp byte [es:si+fb_bits],0 - jz prim_videomodes_40 - add si,sizeof_fb_entry - inc eax - loop prim_videomodes_20 -prim_videomodes_40: - mov dl,t_int - xor cx,cx - call set_pstack_tos -prim_videomodes_90: - ret - - -;; getvideomode - get mode from boot loader list -; -; group: system -; -; ( int1 -- int2 int3 int4 int5 ) -; -; int1: mode index (see @videomodes) -; int2: BIOS mode number -; int3: width -; int4: height -; int5: 1: with framebuffer support -; -prim_getvideomode: - mov dl,t_int - call get_1arg - jc prim_getvm_90 - mov bp,pserr_invalid_range - mov fs,[boot_cs] - mov si,[boot_sysconfig] - movzx ecx,byte [fs:si+4] - cmp eax,ecx - cmc - jc prim_getvm_90 - imul di,ax,sizeof_fb_entry - add di,[fs:si+2] - - mov ax,[pstack_ptr] - add ax,3 - cmp [pstack_size],ax - mov bp,pserr_pstack_overflow - jb prim_getvm_90 - mov [pstack_ptr],ax - - mov dl,t_int - movzx eax,word [fs:di+fb_mode] - mov cx,3 - call set_pstack_tos - - mov dl,t_int - movzx eax,word [fs:di+fb_width] - mov cx,2 - call set_pstack_tos - - mov dl,t_int - movzx eax,word [fs:di+fb_height] - mov cx,1 - call set_pstack_tos - - mov dl,t_int - movzx eax,byte [fs:di+fb_ok] - xor cx,cx - call set_pstack_tos -prim_getvm_90: - ret - - ;; usleep - sleep micro seconds ; ; group: system @@ -13916,3 +13900,192 @@ mouse_handler: retf +; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +; +; Get monitor capabilities. +; +; +get_monitor_res: + call read_ddc + call read_fsc + + ; convert timing bitmask to resolution + ; if the card has enough memory assume larger resolutions + + mov ax,[ddc_timings] + mov dword [ddc_xtimings],640 + (480 << 16) + test ax,0ef03h + jnz get_mon_res_20 + cmp word [screen_mem],0x3e ; at least 4MB-128k + jb get_mon_res_21 +get_mon_res_20: + mov dword [ddc_xtimings],800 + (600 << 16) +get_mon_res_21: + test ax,0f00h + jnz get_mon_res_22 + cmp word [screen_mem],0x200 ; at least 32MB + jb get_mon_res_23 +get_mon_res_22: + mov dword [ddc_xtimings],1024 + (768 << 16) +get_mon_res_23: + test ax,0100h + jz get_mon_res_24 + mov dword [ddc_xtimings],1280 + (1024 << 16) +get_mon_res_24: + + ; find max. resolution + + mov cx,5 + mov si,ddc_xtimings + +get_mon_res_30: + mov ax,[si] + mov dx,[si+2] + + cmp ax,[ddc_xtimings] + jb get_mon_res_60 + + cmp dx,[ddc_xtimings+2] + jb get_mon_res_60 + + mov [ddc_xtimings],ax + mov [ddc_xtimings+2],dx + +get_mon_res_60: + add si,4 + loop get_mon_res_30 + + ret + + +; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +; +; Read EDID record via DDC +; +read_ddc: + push es + + ; vbe support check + cmp word [screen_mem],0 + jz read_ddc_90 + + xor cx,cx + xor dx,dx + mov ax,4f15h + mov bl,0 + int 10h + cmp ax,4fh + jnz read_ddc_90 + + les di,[vbe_buffer] + push di + mov cx,40h + xor ax,ax + rep stosw + pop di + mov ax,4f15h + mov bl,1 + xor cx,cx + xor dx,dx + push di + int 10h + pop di + cmp ax,4fh + jnz read_ddc_90 + + mov ax,[es:di+23h] + mov [ddc_timings],ax + + mov cx,4 + lea si,[di+26h] + mov di,ddc_xtimings1 +read_ddc_40: + es lodsb + cmp al,1 + jbe read_ddc_70 + + movzx ebp,al + add bp,byte 31 + shl bp,3 + + mov al,[es:si] + shr al,6 + jz read_ddc_70 + movzx bx,al + shl bx,3 + + mov eax,ebp + mul dword [bx+ddc_mult] + div dword [bx+ddc_mult+4] + + jz read_ddc_70 + + shl eax,16 + add eax,ebp + mov [di],eax + +read_ddc_70: + inc si + add di,4 + loop read_ddc_40 + +read_ddc_90: + pop es + ret + +ddc_timings dw 0 ; standard ddc timing info +ddc_xtimings dd 0 ; converted standard timing/final timing value +ddc_xtimings1 dd 0, 0, 0, 0 +ddc_mult dd 0, 1 ; needed for ddc timing calculation + dd 3, 4 + dd 4, 5 + dd 9, 16 + + +; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +; look for a fsc notebook lcd panel and set ddc_timings +read_fsc: + push es + push ds + cmp word [ddc_timings],byte 0 + jnz read_fsc_90 + + push word 0xf000 + pop ds + xor di,di +read_fsc_10: + cmp dword [di],0x696a7546 + jnz read_fsc_30 + cmp dword [di+4],0x20757374 + jnz read_fsc_30 + mov cx,0x20 + xor bx,bx + mov si,di +read_fsc_20: + lodsb + add bl,al + dec cx + jnz read_fsc_20 + or bl,bl + jnz read_fsc_30 + mov al,[di+23] + and al,0xf0 + jnz read_fsc_90 + mov bl,[di+21] + and bx,0xf0 + shr bx,3 + mov ax,[cs:bx+fsc_bits] + mov [cs:ddc_timings],ax + jmp read_fsc_90 +read_fsc_30: + add di,0x10 + jnz read_fsc_10 +read_fsc_90: + pop ds + pop es + ret + +fsc_bits dw 0, 0x0004, 0x4000, 0x0200, 0x0100, 0x0200, 0, 0x4000 + dw 0x0200, 0, 0, 0, 0, 0, 0, 0 + + diff --git a/mk_vocabulary b/mk_vocabulary index 8e812a1..1750b55 100755 --- a/mk_vocabulary +++ b/mk_vocabulary @@ -17,7 +17,7 @@ trace dtrace malloc free memsize dumpmem gettype settype - screen.size image.colors vscreen.size + screen.size image.colors vscreen.size monitorsize moveto currentpoint lineto setcolor currentcolor putpixel getpixel setfont currentfont fontheight strsize show settextmodecolor image loadpalette tint settintcolor setpalette getpalette @@ -45,8 +45,6 @@ lineheight currenttitle - videomodes getvideomode - usleep notimeout time date setbrightness currentbrightness @@ -61,7 +59,7 @@ getbyte putbyte getdword putdword findfile filesize getcwd chdir - setmode currentmode findmode + setmode currentmode videomodeinfo videomodes colorbits setimage currentimage diff --git a/themes/SuSE/common.inc b/themes/SuSE/common.inc index e068d5f..592bce9 100644 --- a/themes/SuSE/common.inc +++ b/themes/SuSE/common.inc @@ -75,7 +75,7 @@ % % Check if there are boot directories for 32 & 64bit. % -% Note: currently assumes /boot//loader. Should be more flexible. +% Assumes 32bit to be in *i386* and 64bit in *x86_64*. % % ( ) ==> ( ) % @@ -86,14 +86,14 @@ dup "i386" strstr 0 ne over "x86_64" strstr 0 ne or { dup "i386" strstr { /32bit_boot_dir exch def - /64bit_boot_dir "/boot/x86_64/loader" + /64bit_boot_dir 32bit_boot_dir "i386" "x86_64" strreplace } { /64bit_boot_dir exch def - /32bit_boot_dir "/boot/i386/loader" + /32bit_boot_dir 64bit_boot_dir "x86_64" "i386" strreplace } ifelse dup "%s/isolinux.cfg" 64bit.tmp sprintf - 64bit.tmp filesize .undef ne { def } { pop pop } ifelse + 64bit.tmp filesize .undef ne { def } { free pop } ifelse } { /32bit_boot_dir over def @@ -354,23 +354,14 @@ } if syslinux { - xmenu.video 0 get 0 eq { - "textmode=1 " bc.cmd dup length add sprintf - } if + video.modes.list xmenu.video .xm_current get get .vm_mode get - video.modes.list xmenu.video .xm_current get get - dup .vm_width get 640 eq - over .vm_height get 480 eq - and { - pop - "x11i=vesa " bc.cmd dup length add sprintf + dup 0 ge { + 0x200 add "vga=0x%x " bc.cmd dup length add sprintf } { - .vm_mode get dup { - "vga=0x%x " bc.cmd dup length add sprintf - } { - pop - } ifelse - + -1 eq { + "textmode=1 " bc.cmd dup length add sprintf + } if } ifelse config.lang { @@ -1617,3 +1608,5 @@ true or { check_arch_boot_dir + + diff --git a/themes/SuSE/dia_video.inc b/themes/SuSE/dia_video.inc index 31bea24..379b6c7 100644 --- a/themes/SuSE/dia_video.inc +++ b/themes/SuSE/dia_video.inc @@ -8,15 +8,15 @@ % - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - % Some global vars. % -% video mode array fields (as returned by getvideomode) +% video mode array fields /.vm_mode 0 def /.vm_width 1 def /.vm_height 2 def -/.vm_ok 3 def % monitor supports it % We have kernel splash images for at least these sizes. /video.splashsizes [ - 640 480 + 0 0 % special: for text mode + 1 0 % special: for VESA mode 800 600 1024 768 1280 1024 @@ -81,31 +81,30 @@ /xmenu xmenu.video def - videomodes 1 add dup array /video.modes.text exch def array /video.modes.list exch def - xmenu .xm_list video.modes.text put - - % add text mode entry - - % [ mode width height supported ] - video.modes.list 0 [ 0 0 0 1 ] put + % build list of video modes + /video.modes.list [ + [ -1 0 0 ] % special: text mode + [ -2 1 0 ] % special: VESA mode (width = 1 to make it sort) - videomodes 0 gt { - 0 1 videomodes 1 sub { - video.modes.list exch [ over getvideomode ] exch 1 add exch put + 0 1 videomodes { + videomodeinfo dup .undef eq { + pop pop pop pop + } { + [ + over 0xbfff and 6 2 roll + 0x4000 and % fb support + exch 0x10 eq and % 16 color bits + over 600 ge and % height >= 600 + 2 index 800 ge and % width >= 800 + { ] } { pop pop pop pop } ifelse + } ifelse } for - } if - % always accept 800x600 - - video.modes.list { - dup .vm_width get 800 eq - over .vm_height get 600 eq - and { .vm_ok 1 put } { pop } ifelse - } forall + ] def % sort video.modes.list - video.modes.list length 1 gt { + video.modes.list length 3 gt { 0 1 video.modes.list length 2 sub { dup 1 add 1 video.modes.list length 1 sub { over vmsortindex over vmsortindex gt { @@ -119,38 +118,42 @@ % create mode strings - 0 1 video.modes.list length 1 sub { - video.modes.text exch - dup video.modes.list exch get - dup .vm_width get 0 eq { - pop "Text Mode" put - } { - dup .vm_width get 640 eq - over .vm_height get 480 eq - and { - pop "VESA" put + /video.modes.text [ + video.modes.list { + dup .vm_width get + dup 0 eq { + pop pop "Text Mode" } { - 32 string dup rot - dup .vm_height get exch .vm_width get - "%d x %d" 4 -1 roll sprintf - put + dup 1 eq { + pop pop "VESA" + } { + exch .vm_height get exch "%d x %d" 32 string dup 5 1 roll sprintf + } ifelse } ifelse - } ifelse - } for + } forall + ] def + + % add to menu - % select first mode - xmenu .xm_current 0 put + xmenu .xm_list video.modes.text put % select largest mode the monitor supports - 0 1 video.modes.list length 1 sub { - video.modes.list over get - dup .vm_ok get 0 gt exch video.havesplash and { - xmenu .xm_current rot put + monitorsize exch 800 max exch 600 max % at least 800x600 + + xmenu .xm_current -1 put + video.modes.list { + dup .vm_width get 3 index le + over .vm_height get 3 index le and + exch video.havesplash and { + xmenu .xm_current over over get 1 add put } { - pop + exit } ifelse - } for + + } forall + + pop pop pmenu.init } def diff --git a/themes/SuSE/system.inc b/themes/SuSE/system.inc index 0cc2a35..ebe0369 100644 --- a/themes/SuSE/system.inc +++ b/themes/SuSE/system.inc @@ -600,3 +600,57 @@ def } def +%% findmode - find video mode number +% +% group: gfx.screen +% +% ( int1 int2 int3 -- int4 ) +% +% int1, int2: width, height +% int3: color bits +% int4: mode number (or .undef) +% +% example +% 1024 768 16 findmode setmode % 1024x768, 16-bit color mode +% +/findmode { + 0 1 videomodes { + videomodeinfo dup .undef eq { + pop pop pop pop + } { + % compare width, height, colors + 6 index 4 index eq 6 index 4 index eq and 5 index 3 index eq and { + 7 1 roll 6 { pop } repeat 0xbfff and return + } { + pop pop pop pop + } ifelse + } ifelse + } for + + pop pop pop .undef +} def + + +% - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +% +% Replace substring. Returns newly allocated string. +% +% ( str key value ) ==> ( new_str ) +% +% Replaces first occurence of 'key' in str with 'value'. +% +/strreplace { + 2 index 2 index strstr dup 0 ne { + 1 sub + over length 3 index length sub 4 index length add string + dup cvp 5 index cvp 3 index memcpy + dup 6 1 roll over add exch 5 -1 roll exch add + 4 -1 roll length add 3 1 roll "%s%s" exch sprintf + } { + pop pop pop strdup + } ifelse + + +} def + + -- cgit v1.2.3