Date: Tue, 21 Jun 2016 23:27:41 +0200 From: Edgar =?iso-8859-1?B?RnXf?= <e...@math.uni-bonn.de> Message-ID: <20160621212740.gl12...@trav.math.uni-bonn.de>
| So it's probably hard to get right. Non trivial yes, some of the things that can be done which have to be undone are var assignments, option changes, redirections, and anything that does a sys call that affects the shell environ (cd, ulimit, ...) | I would hope for 3. so one could plug that code (or concept) into ash. Unfortunately the issues relate to the whole structure of the shell. If you want ksh93, you can just use it, copying its source code to src/bin/sh and calling it the NetBSD shell wouldn't really achieve anything useful. The "whole structure" includes the way the shell does memory management (it deals with LOTS of temporary strings, etc) error handling, ... | Or a function. Yes. | Whereas, with a function, one could circumvent the problem by making the | function assign the result to a global variable instead of printing it. Often, yes. | > But in some cases, depending upon exactly what the printf is doing, | > there can be other ways. | Yes, please? The stuff that is doing base conversion (or appears to be here) isn't going to be trivial (of course, one could write a function to do it using basic arithmetic ( $(( )) ), but that's not going to be very quick most likely) | The printf's are like | printf "%02X%02X:%02X%02X" "$@" | or | printf "%04X" 0x"$xyz" I think those two are just the same thing right? That is, print a hex number (string) in a fixed width field with leading 0's, using upper case A-F for the >=10 hex digits (whether the input is upper or lower) To take just the second one (the first is just the same thing, more or less, 4 times, and just 2 digits each, with a : stuck in the middle...) assuming "$@" contains data that is already explicitly hex - if it is actually doing base conversion (11 --> B) then it would need extra help. There are two parts to that, one to convert lower case to upper ... while : do case "${xyz}" in *a*) xyz=${xyz%a*}A${xyz#*a} ;; *b*) xyz=${xyz%b*}B${xyz#*b} ;; # same for c d e f *) break;; esac done and then to make it (at least) 4 chars long with leading 0's as required case "${xyz}" in ?) xyz=000${xyz} ;; ??) xyz=00${xyz} ;; ???) xyz=0${xyz} ;; esac whether that ends up being faster than a fork and printf I have no idea. | or | printf "%0$(( 33 - ${#xyz} ))X" 0 That's (I think) making a long string of 0's enough so that when $xyz is appended it will be 33 chars long p= # the result is in p while : do case $(( 33 - ${#p} - ${#xyz} )) in 0) break ;; 1) p=0$p; break;; 2) p=00$p; break;; 3) p=000$p; break;; 4) p=0000$p; break;; *) p=00000$p;; esac done Obviously you can add more cases to make the loop iterate less, in the extreme you could enumerate all 33 cases and remove the loop completely (in that case you also don't need ${#p} as that would simply be 0) | printf "%x" 0x"$(printf "%.4s" "${xyz}")" That one is just extracting the first 4 chars of the string, converting hex to lower case, and omitting leading 0's. I'l omit the case conversion part (can be done as above, backwards) what's left is ... x=${xyz} # x is going to be the answer case "${x}" in ?|??|???|????) ;; *) y=${x#????}; x=${x%${y}};; esac x=${x##0} test -z "${x}" && x=0 | or | printf "%.$(($2 / 4))s%s\n" "$1" "${3#$(printf "%.$(($2 / 4))s" "$3")}" This is slightly trickier, as the length to be extracted from each string is variable, but it can be done too ($2 is obviously a bit length, so $2/4 is the number of hex digits - except that it is broken for any but count that isn't an even multiple of 4 ( for 17 you'd get 4 chars, whereas 5 are really needed - with some bits forced 0). Unless any of this was going to be in very heavily used code, I wouldn't even think of any of this however, doing it the simple clear way almost always wins - people time is generally far more important than a few cpu cycles. kre