Upload Tizen:Base source
[external/bash.git] / examples / scripts / dd-ex.sh
1 #!/bin/sh
2
3 # this is a line editor using only /bin/sh, /bin/dd and /bin/rm
4
5 # /bin/rm is not really required, but it is nice to clean up temporary files
6
7 PATH=
8 dd=/bin/dd
9 rm=/bin/rm
10
11 # temporary files we might need
12 tmp=/tmp/silly.$$
13 ed=/tmp/ed.$$
14 trap "$rm -f $tmp $tmp.1 $tmp.2 $tmp.3 $tmp.4 $tmp.5 $tmp.6 $ed.a $ed.b $ed.c; exit" 0 1 2 3
15
16 # from now on, no more rm - the above trap is enough
17 unset rm
18
19 # we do interesting things with IFS, but better save it...
20 saveIFS="$IFS"
21
22 # in case "echo" is not a shell builtin...
23
24 Echo () {
25 case "$1" in
26   -n) shift
27       $dd of=$tmp 2>/dev/null <<EOF 
28 $@
29 EOF
30       IFS="+"
31       set `$dd if=$tmp bs=1 of=/dev/null skip=1 2>&1`
32       IFS="$saveIFS"
33       $dd if=$tmp bs=1 count=$1 2>/dev/null
34       ;;
35   *)  $dd 2>/dev/null <<EOF 
36 $@
37 EOF
38       ;;
39 esac
40 }
41
42 # this is used to generate garbage files
43
44 true () {
45   return 0
46 }
47
48 false () {
49   return 1
50 }
51
52 zero () {
53   ( trap 'go=false' 13
54     go=true
55     while $go
56     do
57       $dd "if=$0"
58       case "$?" in
59         0) ;;
60         *) go=false ;;
61       esac
62     done
63   ) 2>/dev/null
64 }
65
66 # arithmetic using dd!
67
68 # add variable n1 n2 n3...
69 # assigns n1+n2+n3+... to variable
70
71 add () {
72   result="$1"
73   shift
74   $dd if=/dev/null of=$tmp bs=1 2>/dev/null
75   for n in "$@"
76   do
77     case "$n" in
78       0) ;;
79       *) zero | $dd of=$tmp.1 bs=1 "count=$n" 2>/dev/null
80          ( $dd if=$tmp; $dd if=$tmp.1 ) 2>/dev/null | $dd of=$tmp.2 2>/dev/null
81          $dd if=$tmp.2 of=$tmp 2>/dev/null
82          ;;
83     esac
84   done
85   IFS="+"
86   set `$dd if=$tmp bs=1 of=/dev/null 2>&1`
87   IFS="$saveIFS"
88   eval $result='$1'
89 }
90
91 # subtract variable n1 n2
92 # subtracts n2 from n1, assigns result to variable
93
94 subtract () {
95   result="$1"
96   zero | $dd of=$tmp bs=1 "count=$2" 2>/dev/null
97   IFS="+"
98   set `$dd if=$tmp bs=1 of=/dev/null "skip=$3" 2>&1`
99   IFS="$saveIFS"
100   case "$1" in
101     dd*) set 0 ;;
102   esac
103   eval $result='$1'
104 }
105
106 # multiply variable n1 n2
107 # variable = n1 * n2
108
109 multiply () {
110   result="$1"
111   zero | $dd "bs=$2" of=$tmp "count=$3" 2>/dev/null
112   IFS="+"
113   set `$dd if=$tmp bs=1 of=/dev/null 2>&1`
114   IFS="$saveIFS"
115   eval $result='$1'
116 }
117
118 # divide variable n1 n2
119 # variable = int( n1 / n2 )
120
121 divide () {
122   result="$1"
123   zero | $dd bs=1 of=$tmp "count=$2" 2>/dev/null
124   IFS="+"
125   set `$dd if=$tmp "bs=$3" of=/dev/null 2>&1`
126   IFS="$saveIFS"
127   eval $result='$1'
128 }
129
130 # compare variable n1 n2 sets variable to lt if n1<n2, gt if n1>n2, eq if n1==n2
131
132 compare () {
133   res="$1"
134   n1="$2"
135   n2="$3"
136   subtract somename "$n1" "$n2"
137   case "$somename" in
138     0) ;;
139     *) eval $res=gt; return;
140   esac
141   subtract somename "$n2" "$n1"
142   case "$somename" in
143     0) ;;
144     *) eval $res=lt; return;
145   esac
146   eval $res=eq
147 }
148
149 # lt n1 n2 returns true if n1 < n2
150
151 lt () {
152   n1="$1"
153   n2="$2"
154   subtract somename "$n2" "$n1"
155   case "$somename" in
156     0) return 1 ;;
157   esac
158   return 0
159 }
160
161 # le n1 n2 returns true if n1 <= n2
162
163 le () {
164   n1="$1"
165   n2="$2"
166   subtract somename "$n1" "$n2"
167   case "$somename" in
168     0) return 0 ;;
169   esac
170   return 1
171 }
172
173 # gt n1 n2 returns true if n1 > n2
174
175 gt () {
176   n1="$1"
177   n2="$2"
178   subtract somename "$n1" "$n2"
179   case "$somename" in
180     0) return 1 ;;
181   esac
182   return 0
183 }
184
185 # ge n1 n2 returns true if n1 >= n2
186
187 ge () {
188   n1="$1"
189   n2="$2"
190   subtract somename "$n2" "$n1"
191   case "$somename" in
192     0) return 0 ;;
193   esac
194   return 1
195 }
196
197 # useful functions for the line editor
198
199 # open a file - copy it to the buffers
200
201 open () {
202   file="$1"
203   set `$dd "if=$file" of=/dev/null 2>&1`
204   case "$1" in
205     dd*) return 1
206   esac
207   # copy the first line to $ed.c
208   go=true
209   len=0
210   while $go
211   do
212     case "`$dd "if=$file" bs=1 skip=$len count=1 2>/dev/null`" in
213       ?*) go=true ;;
214       *) go=false ;;
215     esac
216     add len 1 $len
217   done
218   # now $len is the length of the first line (including newline)
219   $dd "if=$file" bs=1 count=$len of=$ed.c 2>/dev/null
220   $dd "if=$file" bs=1 skip=$len of=$ed.b 2>/dev/null
221   $dd if=/dev/null of=$ed.a 2>/dev/null
222   lineno=1
223 }
224
225 # save a file - copy the buffers to the file
226
227 save () {
228   # make a backup copy of the original
229   $dd "if=$1" "of=$1.bak" 2>/dev/null
230   # and save
231   ( $dd if=$ed.a; $dd if=$ed.c; $dd if=$ed.b ) > "$1" 2>/dev/null
232 }
233
234 # replace n1 n2 bla replaces n2 chars of current line, starting n1-th
235
236 replace () {
237   $dd if=$ed.c of=$tmp.1 bs=1 "count=$1" 2>/dev/null
238   ( $dd if=$ed.c "skip=$1" bs=1 | $dd of=$tmp.2 bs=1 "skip=$2" ) 2>/dev/null
239   shift
240   shift
241   ( $dd if=$tmp.1; Echo -n "$@"; $dd if=$tmp.2 ) > $tmp.3 2>/dev/null
242   $dd if=$tmp.3 of=$ed.c 2>/dev/null
243 }
244
245 # rstring n s bla
246 # replace the n-th occurence of s with bla
247
248 rstring () {
249   n="$1"
250   shift;
251   # first we have to find it - this is fun!
252   # we have $tmp.4 => text before string, $tmp.5 => text after
253   $dd if=/dev/null of=$tmp.4 2>/dev/null
254   $dd if=$ed.c of=$tmp.5 2>/dev/null
255   string="$1"
256   shift
257   $dd of=$tmp.6 2>/dev/null <<EOF
258 $@
259 EOF
260   while :
261   do
262     case "`$dd if=$tmp.5 2>/dev/null`" in
263       $string*)
264           if lt $n 2
265           then
266             # now we want to replace the string
267             Echo -n "$@" > $tmp.2
268             Echo -n "$string" > $tmp.1
269             IFS="+"
270             set `$dd bs=1 if=$tmp.1 of=/dev/null 2>&1`
271             IFS="$saveIFS"
272             slen=$1
273             IFS="+"
274             ( $dd if=$tmp.4; $dd if=$tmp.2; $dd if=$tmp.5 bs=1 skip=$slen ) \
275                   2>/dev/null > $tmp
276             $dd if=$tmp of=$ed.c 2>/dev/null
277             return 0
278           else
279             subtract n $n 1
280             ( $dd if=$tmp.4; $dd if=$tmp.5 bs=1 count=1 ) > $tmp 2>/dev/null
281             $dd if=$tmp of=$tmp.4 2>/dev/null
282             # and remove it from $tmp.5
283             $dd if=$tmp.5 of=$tmp bs=1 skip=1 2>/dev/null
284             $dd if=$tmp of=$tmp.5 2>/dev/null
285           fi
286           ;;
287       ?*) # add one more byte...
288           ( $dd if=$tmp.4; $dd if=$tmp.5 bs=1 count=1 ) > $tmp 2>/dev/null
289           $dd if=$tmp of=$tmp.4 2>/dev/null
290           # and remove it from $tmp.5
291           $dd if=$tmp.5 of=$tmp bs=1 skip=1 2>/dev/null
292           $dd if=$tmp of=$tmp.5 2>/dev/null
293           ;;
294       *)  # not found
295           return 1
296           ;;
297     esac
298   done
299 }
300
301 # skip to next line
302 next () {
303   add l $lineno 1
304   ( $dd if=$ed.a; $dd if=$ed.c ) 2>/dev/null > $tmp.3
305   $dd if=$ed.b of=$tmp.4 2>/dev/null
306   open $tmp.4
307   $dd if=$tmp.3 of=$ed.a 2>/dev/null
308   lineno=$l
309 }
310
311 # delete current line
312 delete () {
313   l=$lineno
314   $dd if=$ed.a 2>/dev/null > $tmp.1
315   $dd if=$ed.b of=$tmp.2 2>/dev/null
316   open $tmp.2
317   $dd if=$tmp.1 of=$ed.a 2>/dev/null
318   lineno=$l
319 }
320
321 # insert before current line (without changing current)
322 insert () {
323   ( $dd if=$ed.a; Echo "$@" ) 2>/dev/null > $tmp.1
324   $dd if=$tmp.1 of=$ed.a 2>/dev/null
325   add lineno $lineno 1
326 }
327
328 # previous line
329 prev () {
330   case "$lineno" in
331     1) ;;
332     *) subtract lineno $lineno 1
333        # read last line of $ed.a
334        IFS='+'
335        set `$dd if=$ed.a of=/dev/null bs=1 2>&1`
336        IFS="$saveIFS"
337        size=$1
338        # empty?
339        case "$size" in
340          0) return ;;
341        esac
342        subtract size $size 1
343        # skip final newline
344        case "$size" in
345          0) ;;
346          *) subtract size1 $size 1
347             case "`$dd if=$ed.a bs=1 skip=$size count=1 2>/dev/null`" in
348               ?*) ;;
349               *) size=$size1 ;;
350             esac
351             ;;
352        esac
353        go=true
354        while $go
355        do
356          case "$size" in
357            0) go=false ;;
358            *) case "`$dd if=$ed.a bs=1 skip=$size count=1 2>/dev/null`" in
359                 ?*)  go=true; subtract size $size 1 ;;
360                 *)   go=false; add size $size 1 ;;
361               esac
362               ;;
363          esac
364        done
365        # now $size is the size of the first n-1 lines
366        # add $ed.c to $ed.b
367        ( $dd if=$ed.c; $dd if=$ed.b ) 2>/dev/null > $tmp.5
368        $dd if=$tmp.5 of=$ed.b 2>/dev/null
369        # move line to ed.c
370        case "$size" in
371          0) $dd if=$ed.a of=$ed.c 2>/dev/null
372             $dd if=/dev/null of=$tmp.5 2>/dev/null
373             ;;
374          *) $dd if=$ed.a of=$ed.c bs=1 skip=$size 2>/dev/null
375             $dd if=$ed.a of=$tmp.5 bs=1 count=$size 2>/dev/null
376             ;;
377        esac
378        # move rest to ed.a
379        $dd if=$tmp.5 of=$ed.a 2>/dev/null
380     ;;
381   esac
382 }
383
384 # goes to a given line
385 goto () {
386   rl="$1"
387   compare bla "$rl" $lineno
388   case "$bla" in
389     eq) return
390         ;;
391     gt) while gt "$rl" $lineno
392         do
393           next
394         done
395         ;;
396     lt) while lt "$rl" $lineno
397         do
398           prev
399         done
400         ;;
401   esac
402 }
403
404 lineout () {
405   Echo -n "$lineno: "
406   $dd if=$ed.c 2>/dev/null
407 }
408
409 state=closed
410 name=
411 autoprint=true
412
413 while true
414 do
415   Echo -n '> '
416   read cmd arg
417   case "$cmd:$state" in
418     open:open) Echo "There is a file open already" ;;
419     open:*) if open "$arg"
420             then state=open; name="$arg"; $autoprint
421             else Echo "Cannot open $arg"
422             fi
423             ;;
424     new:open) Echo "There is a file open already" ;;
425     new:*)  open "$arg"
426             state=open
427             name="$arg"
428             $autoprint
429             ;;
430     close:changed) Echo "Use 'discard' or 'save'" ;;
431     close:closed) Echo "Closed already" ;;
432     close:*) state=closed ;;
433     save:closed) Echo "There isn't a file to save" ;;
434     save:*) case "$arg" in
435               ?*) save "$arg" ;;
436               *) save "$name" ;;
437             esac
438             state=open
439             ;;
440     discard:changed) Echo "Your problem!"; state=closed ;;
441     discard:*) state=closed ;;
442     print:closed) Echo "No current file" ;;
443     print:*) lineout ;;
444     goto:closed) Echo "No current file" ;;
445     goto:*) goto "$arg"; $autoprint ;;
446     next:closed) Echo "No current file" ;;
447     next:*) next; $autoprint ;;
448     prev:closed) Echo "No current file" ;;
449     prev:*) prev; $autoprint ;;
450     name:closed) Echo "No current file" ;;
451     name:*) name="$arg" ;;
452     replace:closed) Echo "No current file" ;;
453     replace:*) if rstring 1 $arg
454                then state=changed; $autoprint
455                else Echo "Not found"
456                fi
457                ;;
458     nreplace:closed) Echo "No current file" ;;
459     nreplace:*) if rstring $arg
460                 then state=changed; $autoprint
461                 else Echo "Not found"
462                 fi
463                 ;;
464     delete:closed) Echo "No current file" ;;
465     delete:*) delete; state=changed; $autoprint ;;
466     insert:closed) Echo "No current file" ;;
467     insert:*) insert "$arg"; prev; state=changed; $autoprint ;;
468     quit:changed) Echo "Use 'save' or 'discard'" ;;
469     quit:*) Echo "bye"; exit;;
470     autoprint:*) autoprint="lineout" ;;
471     noprint:*) autoprint="" ;;
472     :*) ;;
473     *) Echo "Command not understood" ;;
474   esac
475 done
476