forçe enough for mplayer to not rely on broken autodetection
[shellsnippets/shellsnippets.git] / mksh / debian-dev / mkdebidx.sh
1 #!/bin/mksh
2 rcsid='$MirOS: contrib/hosted/tg/deb/mkdebidx.sh,v 1.74 2016/11/05 16:45:56 tg Exp $'
3 #-
4 # Copyright © 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016
5 #       mirabilos <m@mirbsd.org>
6 #
7 # Provided that these terms and disclaimer and all copyright notices
8 # are retained or reproduced in an accompanying document, permission
9 # is granted to deal in this work without restriction, including un-
10 # limited rights to use, publicly perform, distribute, sell, modify,
11 # merge, give away, or sublicence.
12 #
13 # This work is provided "AS IS" and WITHOUT WARRANTY of any kind, to
14 # the utmost extent permitted by applicable law, neither express nor
15 # implied; without malicious intent or gross negligence. In no event
16 # may a licensor, author or contributor be held liable for indirect,
17 # direct, other damage, loss, or other issues arising in any way out
18 # of dealing in the work, even if advised of the possibility of such
19 # damage or existence of a defect, except proven that it results out
20 # of said person's immediate fault when using the work as intended.
21
22 unset normarchs repo_keyid gpg_remote gpg_bin repo_origin repo_label repo_title
23 unset -f repo_intro repo_description
24 me=$(dirname "$0"); [[ -s $me/mkdebidx.inc ]] && . "$me/mkdebidx.inc"
25 unset me
26
27 [[ -n ${normarchs+x} ]] || set -A normarchs -- i386
28 # either '' (locally) or 'remsign user@host.domain.com' (remote ssh)
29 [[ -n ${repo_keyid+x} ]] || repo_keyid=0xAA917C6F
30 [[ -n ${gpg_remote+x} ]] || gpg_remote=
31 case ${gpg_bin:-x} {
32 (gpg|gpg1|gpg2|gnupg|gnupg1|gnupg2) ;;
33 (*)
34         if [[ -n $gpg_remote ]]; then
35                 gpg_bin=gpg
36         elif ! gpg_bin=$(whence -p gpg1); then
37                 gpg_bin=gpg
38         fi
39         ;;
40 }
41 [[ -n ${repo_origin+x} ]] || repo_origin='The MirOS Project'
42 [[ -n ${repo_label+x} ]] || repo_label=wtf
43 [[ -n ${repo_title+x} ]] || repo_title='MirDebian “WTF” Repository'
44 typeset -f repo_intro >/dev/null || function repo_intro {
45         cat <<-'EOF'
46         <p>This APT repository contains packages by mirabilos (<i>wtf</i>)
47          for use with the Debian operating system and its derivates. It is
48          not affiliated with Debian. Some of the content is merely hosted
49          for people close to MirBSD or Debian; some is affiliated with The
50          MirOS Project.<br /><i>Debian</i> is a registered trademark owned
51          by Software in the Public Interest, Inc.<br />“The MirOS Project”
52          and “MirBSD” are unregistered trademarks owned by mirabilos.</p>
53 EOF
54 }
55 typeset -f repo_description >/dev/null || function repo_description {
56         typeset suite_nick=$1
57
58         print -nr -- "WTF ${suite_nick} Repository"
59 }
60 set -A dpkgarchs -- alpha amd64 arm arm64 armel armhf hppa hurd-i386 i386 \
61     ia64 kfreebsd-amd64 kfreebsd-i386 m68k mips mipsel powerpc powerpcspe \
62     ppc64 ppc64el s390 s390x sh4 sparc sparc64 x32
63 [[ -n "${normarchs[*]}" ]] || set -A normarchs -- "${dpkgarchs[@]}"
64
65 set +U
66 export LC_ALL=C
67 unset LANGUAGE
68 typeset -Z11 -Uui16 hv
69
70 function remsign {
71         target=$1; shift
72         master=remsign.ctl$$
73         tmpfnm=remsign.tmp$$
74         ssh -fNM -o ControlPath=$tmpfnm "$target"
75         ssh -o ControlPath=$tmpfnm "$target" cat \>$tmpfnm
76         ssh -o ControlPath=$tmpfnm -t "$target" "$* $tmpfnm" 0<&2 1>&2
77         rv=$?
78         ssh -o ControlPath=$tmpfnm "$target" "cat $tmpfnm.asc; rm -f $tmpfnm $tmpfnm.asc"
79         ssh -o ControlPath=$tmpfnm "$target" -O exit
80         return $rv
81 }
82
83 function die {
84         local rv=1
85
86         if [[ $1 = +([0-9]) ]]; then
87                 rv=$1
88                 shift
89         fi
90         print -ru2 -- "E: $*"
91         exit $rv
92 }
93
94 function checkedhash {
95         if [[ $1 = size ]]; then
96                 REPLY=$(stat -c '%s' "$2")
97                 [[ $REPLY = +([0-9]) ]] || die "Error getting size of '$2'"
98         else
99                 set -o noglob
100                 set -A REPLY -- $($1 "$2")
101                 set +o noglob
102                 [[ $REPLY = +([0-9a-f]) ]] || die "Error getting $1 of '$2'"
103         fi
104 }
105
106 function putfile {
107         tee $1 | gzip -n9 >$1.gz
108 }
109
110 function sortlist {
111         typeset x u=$1
112
113         if [[ $u = -u ]]; then
114                 shift
115         else
116                 u=
117         fi
118
119         for x in "$@"; do
120                 print -r -- "$x"
121         done | sort $u
122 }
123
124 # escape XHTML characters (three mandatory XML ones plus double quotes,
125 # the latter in an XML safe fashion numerically though)
126 function xhtml_escape {
127         if (( $# )); then
128                 print -nr -- "$@"
129         else
130                 cat
131         fi | sed \
132             -e 's\ 1&\ 1\&amp;\ 1g' \
133             -e 's\ 1<\ 1\&lt;\ 1g' \
134             -e 's\ 1>\ 1\&gt;\ 1g' \
135             -e 's\ 1"\ 1\&#34;\ 1g'
136 }
137
138 cd "$(dirname "$0")"
139 rm -f dpkg_578162_workaround
140
141 IFS=:; set -o noglob
142 dpkgarchl=:all:"${dpkgarchs[*]}":
143 IFS=$' \t\n'; set +o noglob
144
145 suites=:
146 for suite in "$@"; do
147         suites=:dists/$suite$suites
148 done
149
150 allsuites=
151 for suite in dists/*; do
152         allsuites="$allsuites${allsuites:+ }${suite##*/}"
153         [[ -h $suite ]] && continue
154         [[ $suites = : || $suites = *:"$suite":* ]] || continue
155         archs=
156         distribution=
157         debootstrap_compat=0
158         . $suite/distinfo.sh
159         suitearchs=${archs:-${normarchs[*]}}
160         components=Components:
161         for dist in $suite/*; do
162                 [[ -d $dist/. ]] || continue
163                 rm -rf $dist/binary-* $dist/source
164                 ovf= oef= osf= om=-m
165                 (( debootstrap_compat )) && om=
166                 [[ -s $dist/override.file ]] && ovf=$dist/override.file
167                 [[ -s $dist/override.extra ]] && oef="-e $dist/override.extra"
168                 [[ -s $dist/override.src ]] && osf="-s $dist/override.src"
169                 components="$components ${dist##*/}"
170                 archs=
171                 [[ -s $dist/distinfo.sh ]] && . $dist/distinfo.sh
172                 set -A distarchs -- $(sortlist -u all ${archs:-$suitearchs})
173                 IFS=:; set -o noglob
174                 distarchl=:"${distarchs[*]}":
175                 IFS=$' \t\n'; set +o noglob
176                 nmds=0
177                 for arch in $(sortlist -u ${distarchs[*]} ${dpkgarchs[*]}) /; do
178                         # put "all" last
179                         [[ $arch = all ]] && continue
180                         [[ $arch = / ]] && arch=all
181                         # create index
182                         if [[ $dpkgarchl != *:"$arch":* ]]; then
183                                 die "Invalid arch '$arch' in $dist"
184                         elif [[ $distarchl != *:"$arch":* ]]; then
185                                 print "\n===> Linking all =>" \
186                                     "${dist#dists/}/$arch/Packages"
187                                 ln -s binary-all $dist/binary-$arch
188                         elif [[ $arch = all ]] && (( nmds == 1 )); then
189                                 print "\n===> Linking $firstmd =>" \
190                                     "${dist#dists/}/all/Packages"
191                                 ln -s binary-$firstmd $dist/binary-all
192                         else
193                                 print "\n===> Creating" \
194                                     "${dist#dists/}/$arch/Packages\n"
195                                 mkdir -p $dist/binary-$arch
196                                 (dpkg-scanpackages $oef $om -a $arch \
197                                     $dist $ovf || \
198                                     echo $? >$dist/binary-$arch/failed) | \
199                                     putfile $dist/binary-$arch/Packages
200                                 [[ -e $dist/binary-$arch/failed ]] && \
201                                     exit $(<$dist/binary-$arch/failed)
202                                 (( nmds++ )) || firstmd=$arch
203                         fi
204                 done
205                 print "\n===> Creating ${dist#dists/}/Sources"
206                 mkdir -p $dist/source
207                 [[ -e dpkg_578162_workaround ]] || (dpkg-scansources $oef $osf \
208                     $dist $ovf || touch dpkg_578162_workaround) | \
209                     putfile $dist/source/Sources
210                 [[ -e dpkg_578162_workaround ]] && (dpkg-scansources $osf \
211                     $dist $ovf || echo $? >$dist/source/failed) | \
212                     putfile $dist/source/Sources
213                 [[ -e $dist/source/failed ]] && exit $(<$dist/source/failed)
214                 print done.
215                 print "\n===> Creating ${dist#dists/}/i18n/Index"
216                 [[ -d $dist/i18n/. ]] || mkdir -p $dist/i18n
217                 [[ -d $dist/i18n/. ]] || die "Cannot create $dist/i18n"
218                 rm -f $dist/i18n/.done
219                 (cd $dist/i18n
220                 tfiles=/
221                 [[ -h .hashcache || ! -f .hashcache ]] && rm -rf .hashcache
222                 for ent in .* *; do
223                         [[ $ent = . || $ent = .. || $ent = .hashcache ]] && continue
224                         [[ -h $ent || -e $ent ]] || continue
225                         if [[ ! -f $ent || $ent != Translation-* ]]; then
226                                 rm -rf "$ent"
227                                 continue
228                         fi
229                         ent=${ent#Translation-}
230                         ent=${ent%.bz2}
231                         [[ $tfiles = */"$ent"/* ]] || tfiles+=$ent/
232                 done
233                 [[ -e .hashcache ]] || :>.hashcache
234                 if [[ $tfiles = / ]]; then
235                         :>Translation-tlh_DE
236                         tfiles=/tlh_DE/
237                 fi
238                 print SHA1: >Index
239                 IFS=/; set -o noglob
240                 set -A tflist -- ${tfiles#/}
241                 IFS=$' \t\n'; set +o noglob
242                 for ent in "${tflist[@]}"; do
243                         ent=Translation-$ent
244                         if [[ $ent -nt $ent.bz2 ]]; then
245                                 if ! bzip2 -9 <"$ent" >"$ent.bz2"; then
246                                         rm -f "$ent.bz2"
247                                         die "bzip2 '$ent' died"
248                                 fi
249                         elif [[ -e $ent ]]; then
250                                 rm -f "$ent"
251                         fi
252                         hash=${|checkedhash sha1sum "$ent.bz2";} || exit 1
253                         hnum=0
254                         grep "^$hash " .hashcache |&
255                         while read -p hsha1 hsize hmd5 hsha2 usha1 usize umd5 usha2; do
256                                 [[ $hsha1 = "$hash" ]] || continue
257                                 hnum=1
258                                 while read -p hsha1 x; do
259                                         # flush coprocess, look for dupes
260                                         [[ $hsha1 = "$hash" ]] && hnum=2
261                                 done
262                                 break
263                         done
264                         hsha1=$hash
265                         if (( hnum != 1 )); then
266                                 [[ -e $ent ]] || \
267                                     if ! bzip2 -d <"$ent.bz2" >"$ent"; then
268                                         rm -f "$ent"
269                                         die "bzip2 '$ent.bz2' died"
270                                 fi
271                                 umd5=${|checkedhash md5sum "$ent";} || exit 1
272                                 hmd5=${|checkedhash md5sum "$ent.bz2";} || exit 1
273                                 usha1=${|checkedhash sha1sum "$ent";} || exit 1
274                                 usha2=${|checkedhash sha256sum "$ent";} || exit 1
275                                 hsha2=${|checkedhash sha256sum "$ent.bz2";} || exit 1
276                                 usize=${|checkedhash size "$ent";} || exit 1
277                                 hsize=${|checkedhash size "$ent.bz2";} || exit 1
278                                 (( hnum )) || print $hsha1 $hsize $hmd5 $hsha2 $usha1 $usize $umd5 $usha2 >>.hashcache
279                         fi
280                         [[ -e $ent ]] && rm -f "$ent"
281                         print -u4 $hsha1 $hsize $hmd5 $hsha2 $usha1 $usize $umd5 $usha2
282                         print -ru5 " $hsha1 $hsize $ent.bz2"
283                         print -ru6 " $umd5 $usize ${dist##*/}/i18n/$ent"
284                         print -ru6 " $hmd5 $hsize ${dist##*/}/i18n/$ent.bz2"
285                         print -ru7 " $usha1 $usize ${dist##*/}/i18n/$ent"
286                         print -ru7 " $hsha1 $hsize ${dist##*/}/i18n/$ent.bz2"
287                         print -ru8 " $usha2 $usize ${dist##*/}/i18n/$ent"
288                         print -ru8 " $hsha2 $hsize ${dist##*/}/i18n/$ent.bz2"
289                 done 4>.hashcache.new 5>>Index 6>.hashcache.md5 7>.hashcache.sha1 8>.hashcache.sha2
290                 rm -f .hashcache
291                 mv -f .hashcache.new .hashcache
292                 :>.done)
293                 [[ -e $dist/i18n/.done ]] || die i18n generation unsuccessful
294                 rm -f $dist/i18n/.done
295                 print done.
296         done
297         print "\n===> Creating ${suite#dists/}/Release"
298         rm -f $suite/Release-*
299         xdone=$(realpath $suite/Release-done)
300         (cat <<-EOF
301                 Origin: ${repo_origin}
302                 Label: ${repo_label}
303                 Suite: ${distribution:-${suite##*/}}
304                 Codename: ${suite##*/}
305                 Date: $(date -Ru)
306                 Architectures: all ${dpkgarchs[*]} source
307                 $components
308                 Description: $(repo_description "$nick")
309                 MD5Sum:
310         EOF
311         exec 4>$suite/Release-sha1
312         exec 5>$suite/Release-sha2
313         print -u4 SHA1:
314         print -u5 SHA256:
315         cd $suite
316         set -A cache_fn
317         set -A cache_md5
318         set -A cache_sha1
319         set -A cache_sha2
320         set -A cache_size
321         for n in Contents-* */{binary-*,i18n,source}/{Index,{Packag,Sourc}es*}; do
322                 [[ -f $n ]] || continue
323                 # realpath-ise $n and cache the checksum
324                 nn=$(realpath "$n")
325                 #XXX once mksh can, use associative arrays instead
326                 hv=16#${nn@#}
327                 # simple hash collision solver by increment
328                 nc=${cache_fn[hv]}
329                 while [[ -n $nc && $nc != "$nn" ]]; do
330                         nc=${cache_fn[++hv]}
331                 done
332                 if [[ $nc = "$nn" ]]; then
333                         nm=${cache_md5[hv]}
334                         ns=${cache_size[hv]}
335                         nsha1=${cache_sha1[hv]}
336                         nsha2=${cache_sha2[hv]}
337                 else
338                         # GNU *sum tools are horridly inefficient
339                         nm=${|checkedhash md5sum "$nn";} || exit 1
340                         nsha1=${|checkedhash sha1sum "$nn";} || exit 1
341                         nsha2=${|checkedhash sha256sum "$nn";} || exit 1
342                         ns=${|checkedhash size "$nn";} || exit 1
343                         cache_md5[hv]=$nm
344                         cache_size[hv]=$ns
345                         cache_fn[hv]=$nn
346                         cache_sha1[hv]=$nsha1
347                         cache_sha2[hv]=$nsha2
348                 fi
349                 print " $nm $ns $n"
350                 print -u4 " $nsha1 $ns $n"
351                 print -u5 " $nsha2 $ns $n"
352                 if [[ $n = */i18n/Index ]]; then
353                         n=${n%Index}
354                         cat "${n}.hashcache.md5"
355                         cat >&4 "${n}.hashcache.sha1"
356                         cat >&5 "${n}.hashcache.sha2"
357                         rm -f "${n}.hashcache."*
358                 fi
359         done
360         :>"$xdone") >$suite/Release-tmp
361         [[ -e $xdone ]] || die Release generation died
362         cat $suite/Release-sha1 $suite/Release-sha2 >>$suite/Release-tmp
363
364         # note: InRelease files can only be safely used by jessie and up.
365         unset use_inrelease
366         . $suite/distinfo.sh
367         rm -f $suite/InRelease $suite/Release $suite/Release.gpg
368         if [[ $use_inrelease = 1 ]]; then
369                 $gpg_remote $gpg_bin -u $repo_keyid --no-comment --clearsign \
370                     <$suite/Release-tmp >$suite/Release-inl
371                 mv -f $suite/Release-inl $suite/InRelease
372         else
373                 $gpg_remote $gpg_bin -u $repo_keyid --no-comment -sab \
374                     <$suite/Release-tmp >$suite/Release-sig
375                 mv -f $suite/Release-tmp $suite/Release
376                 mv -f $suite/Release-sig $suite/Release.gpg
377         fi
378         rm -f $suite/Release-*
379 done
380
381 print "\n===> Creating debidx.htm\n"
382
383 set -A preplsrc
384 set -A prepldst
385 integer nsrc=0 nbin=0 nrpl=0
386 br='<br />'
387
388 # syntax:       ${suitename}/${distname}/${pN}/${pp} <suite>
389 # example:      sid/wtf/openntpd/i386 lenny
390 if [[ -s mkdebidx.lnk ]]; then
391         while read pn pd; do
392                 [[ $pn = '#'* ]] && continue
393                 if [[ $pn != +([a-z0-9_])/+([a-z0-9_-])/+([!/])/@(%|=|+([a-z0-9])) || \
394                     $pd != +([a-z0-9_]) ]]; then
395                         print -u2 "W: Invalid lnk line '$pn' '$pd'"
396                         continue
397                 fi
398                 preplsrc[nrpl]=$pn
399                 prepldst[nrpl++]=$pd
400         done <mkdebidx.lnk
401 fi
402
403 for suite in dists/*; do
404         [[ -h $suite ]] && continue
405         for dist in $suite/*; do
406                 [[ -d $dist/. ]] || continue
407                 suitename=${suite##*/}
408                 if [[ $suitename != +([a-z0-9_]) ]]; then
409                         print -u2 "W: Invalid suite name '$suitename'"
410                         continue 2
411                 fi
412                 distname=${dist##*/}
413                 if [[ $distname != +([a-z0-9_-]) ]]; then
414                         print -u2 "W: Invalid dist name '$distname'"
415                         continue
416                 fi
417
418                 gzip -dc $dist/source/Sources.gz |&
419                 pn=; pv=; pd=; pp=; Lf=
420                 while IFS= read -pr line; do
421                         case $line {
422                         (" "*)
423                                 if [[ -n $Lf ]]; then
424                                         eval x=\$$Lf
425                                         x=$x$line
426                                         eval $Lf=\$x
427                                 fi
428                                 ;;
429                         ("Package: "*)
430                                 pn=${line##Package:*([   ])}
431                                 Lf=pn
432                                 ;;
433                         ("Version: "*)
434                                 pv=${line##Version:*([   ])}
435                                 Lf=pv
436                                 ;;
437                         ("Binary: "*)
438                                 pd=${line##Binary:*([    ])}
439                                 Lf=pd
440                                 ;;
441                         ("Directory: "*)
442                                 pp=${line##Directory:*([         ])}
443                                 Lf=pp
444                                 ;;
445                         (?*)    # anything else
446                                 Lf=
447                                 ;;
448                         (*)     # empty line
449                                 if [[ -n $pn && -n $pv && -n $pd && -n $pp ]]; then
450                                         i=0
451                                         while (( i < nsrc )); do
452                                                 [[ ${sp_name[i]} = "$pn" && \
453                                                     ${sp_dist[i]} = "$distname" ]] && break
454                                                 let i++
455                                         done
456                                         if (( i == nsrc )); then
457                                                 let nsrc++
458                                                 pvo=
459                                                 ppo=
460                                         else
461                                                 eval pvo=\$\{sp_ver_${suitename}[i]\}
462                                                 eval ppo=\$\{sp_dir_${suitename}[i]\}
463                                         fi
464                                         sp_name[i]=$pn
465                                         sp_dist[i]=$distname
466                                         #sp_suites[i]="${sp_suites[i]} $suitename"
467                                         if (( nrpl )); then
468                                                 x=${suitename}/${distname}/${pn}/source
469                                                 j=0
470                                                 while (( j < nrpl )); do
471                                                         [[ ${preplsrc[j]} = "$x" ]] && break
472                                                         let j++
473                                                 done
474                                                 (( j < nrpl )) && pv="${pv}\1afrom ${prepldst[j]}"
475                                         fi
476                                         eval sp_ver_${suitename}[i]='${pvo:+$pvo,}$pv'
477                                         eval sp_dir_${suitename}[i]='${ppo:+$ppo,}$pp/'
478                                         sp_desc[i]=${sp_desc[i]},$pd
479                                 fi
480                                 pn=; pv=; pd=; pp=; Lf=
481                                 ;;
482                         }
483                 done
484
485                 gzip -dc $(for f in $dist/binary-*/Packages.gz; do
486                         [[ -e $f ]] || continue
487                         realpath "$f"
488                 done | sort -u) |&
489                 pn=; pv=; pd=; pp=; pN=; pf=; pABP=; Lf=
490                 while IFS= read -pr line; do
491                         case $line {
492                         (" "*)
493                                 if [[ -n $Lf ]]; then
494                                         eval x=\$$Lf
495                                         x=$x$line
496                                         eval $Lf=\$x
497                                 fi
498                                 ;;
499                         ("Package: "*)
500                                 pN=${line##Package:*([   ])}
501                                 Lf=pN
502                                 ;;
503                         ("Source: "*)
504                                 pn=${line##Source:*([    ])}
505                                 pn=${pn%% *}
506                                 Lf=pn
507                                 ;;
508                         ("Version: "*)
509                                 pv=${line##Version:*([   ])}
510                                 Lf=pv
511                                 ;;
512                         ("Description: "*)
513                                 pd=${line##Description:*([       ])}
514                                 ;;
515                         ("Architecture: "*)
516                                 pp=${line##Architecture:*([      ])}
517                                 Lf=pp
518                                 ;;
519                         ("Filename: "*)
520                                 pf=${line##Filename:*([  ])}
521                                 Lf=pf
522                                 ;;
523                         ("Auto-Built-Package: "*)
524                                 pABP=${line##Auto-Built-Package:*([      ])}
525                                 Lf=pABP
526                                 ;;
527                         (?*)    # anything else
528                                 Lf=
529                                 ;;
530                         (*)     # empty line
531                                 [[ $pf = *:* || $pf = *'%'* ]] && \
532                                     die Illegal character in $dist \
533                                     packages $pp "'Filename: $pf'"
534                                 [[ -n $pn ]] || pn=$pN
535                                 if [[ $pN = *-dbgsym && $pABP = debug-symbols ]]; then
536                                         : skip
537                                 elif [[ -n $pn && -n $pv && -n $pd && -n $pp ]]; then
538                                         i=0
539                                         while (( i < nbin )); do
540                                                 [[ ${bp_disp[i]} = "$pN" && ${bp_desc[i]} = "$pd" && \
541                                                     ${bp_dist[i]} = "$distname" ]] && break
542                                                 let i++
543                                         done
544                                         (( i == nbin )) && let nbin++
545                                         bp_name[i]=$pn
546                                         bp_disp[i]=$pN
547                                         bp_dist[i]=$distname
548                                         #bp_suites[i]="${bp_suites[i]} $suitename"
549                                         if (( nrpl )); then
550                                                 x=${suitename}/${distname}/${pN}/${pp}
551                                                 j=0
552                                                 while (( j < nrpl )); do
553                                                         [[ ${preplsrc[j]} = "$x" ]] && break
554                                                         let j++
555                                                 done
556                                                 (( j < nrpl )) && pv="from ${prepldst[j]}"
557                                         fi
558                                         [[ -n $pf ]] && pv="<a href=\"$pf\">$pv</a>"
559                                         pv="$pp: $pv"
560                                         eval x=\${bp_ver_${suitename}[i]}
561                                         [[ $br$x$br = *"$br$pv$br"* ]] || x=$x${x:+$br}$pv
562                                         eval bp_ver_${suitename}[i]=\$x
563                                         bp_desc[i]=$pd
564                                 fi
565                                 pn=; pv=; pd=; pp=; pN=; pf=; pABP=; Lf=
566                                 ;;
567                         }
568                 done
569         done
570 done
571
572 (cat <<'EOF'
573 <?xml version="1.0"?>\r
574 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
575  "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
576 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"><head>
577  <meta http-equiv="content-type" content="text/html; charset=utf-8" />
578  <meta name="MSSmartTagsPreventParsing" content="TRUE" />
579 EOF
580 print -r -- " <title>${repo_title} Index</title>"
581 [[ -s NEWS.rss ]] && print '<link rel="alternate" type="application/rss+xml" title="RSS" href="NEWS.rss" />'
582 cat <<'EOF'
583  <style type="text/css"><!--/*--><![CDATA[/*><!--*/
584   table {
585    border: 1px solid black;
586    border-collapse: collapse;
587    text-align: left;
588    vertical-align: top;
589   }
590   tr {
591    border: 1px solid black;
592    text-align: left;
593    vertical-align: top;
594   }
595   td {
596    border: 1px solid black;
597    text-align: left;
598    vertical-align: top;
599   }
600   th {
601    background-color: #000000;
602    color: #FFFFFF;
603   }
604   .tableheadcell {
605    border: 1px solid #999999;
606    padding: 3px;
607    white-space: nowrap;
608   }
609   .srcpkgline {
610    background-color: #CCCCCC;
611   }
612   .srcpkgdist {
613    background-color: #666666;
614    color: #FFFFFF;
615    font-weight: bold;
616   }
617   .binpkgdist {
618    background-color: #999999;
619    color: #FFFFFF;
620    font-weight: bold;
621   }
622  /*]]>*/--></style>
623 </head><body>
624 EOF
625 print -r -- "<h1>${repo_title}</h1>"
626 repo_intro
627 cat <<'EOF'
628 <p><a href="dists/">Browse</a> the repository or read about how to amend <a
629  href="sources.txt">/etc/apt/sources.list</a> in order to use it.
630 EOF
631 [[ -s 0-NOTE.txt ]] && print ' Also read my <a href="0-NOTE.txt">notes</a>.'
632 [[ -s NEWS.rss ]] && print ' There is an <a href="NEWS.rss">RSS newsfeed</a>.'
633 cat <<EOF
634  This repository uses <a
635   href="http://pgp.uni-mainz.de:11371/pks/lookup?search=${repo_keyid}&amp;op=vindex">${repo_keyid}</a>
636  as signing key.
637 </p>
638 <h2>Suites</h2>
639 <ul>
640 EOF
641
642 allsuites=$(for suitename in $allsuites; do
643         print $suitename
644 done | sort -u)
645
646 for suitename in $allsuites; do
647         suite=dists/$suitename
648         if [[ -h $suite ]]; then
649                 ent=$(realpath "$suite")
650                 n=$(realpath dists)
651                 [[ $ent = "$n"/+([!/]) ]] || continue
652                 ent=${ent#"$n"/}
653                 for n in $allsuites; do
654                         [[ $n = "$ent" ]] && break
655                 done
656                 [[ $n = "$ent" ]] && print -r \
657                     " <li>$suitename: symbolic link to $ent</li>"
658                 continue
659         fi
660         . $suite/distinfo.sh
661         print -n " <li>${suite##*/}: <a href=\"$suite/\">$desc</a> (dists:"
662         for dist in $suite/*; do
663                 [[ -d $dist/. ]] || continue
664                 distname=${dist##*/}
665                 print -n " <a href=\"$suite/$distname/\">$distname</a>"
666         done
667         print ")</li>"
668 done
669 print "</ul>"
670 print "<h2>Packages</h2>"
671 print "<table width=\"100%\"><thead>"
672 print "<tr class=\"tablehead\">"
673 print " <th class=\"tableheadcell\">dist</th>"
674 print " <th class=\"tableheadcell\" rowspan=\"2\">Binary / Description</th>"
675 for suitename in $allsuites; do
676         [[ -h dists/$suitename ]] && continue
677         print " <th class=\"tableheadcell\" rowspan=\"2\">$suitename</th>"
678 done
679 print "</tr><tr class=\"tablehead\">"
680 print " <th class=\"tableheadcell\">package name</th>"
681 print "</tr></thead><tbody>"
682
683 set -A bp_sort
684 i=0
685 while (( i < nbin )); do
686         print $i ${bp_disp[i++]} #${bp_suites[i]}
687 done | sort -k2 |&
688 while read -p num rest; do
689         bp_sort[${#bp_sort[*]}]=$num
690 done
691
692 i=0
693 while (( i < nsrc )); do
694         print $i ${sp_name[i++]}
695 done | sort -k2 |&
696 while read -p num rest; do
697         print "\n<!-- sp #$num = ${sp_name[num]} -->"
698         print "<tr class=\"srcpkgline\">"
699         print " <td class=\"srcpkgdist\">${sp_dist[num]}</td>"
700         pd=
701         for x in $(tr ', ' '\n' <<<"${sp_desc[num]}" | sort -u); do
702                 [[ -n $x ]] && pd="$pd, $x"
703         done
704         print " <td rowspan=\"2\" class=\"srcpkgdesc\">${pd#, }</td>"
705         for suitename in $allsuites; do
706                 [[ -h dists/$suitename ]] && continue
707                 eval pvo=\${sp_ver_${suitename}[num]}
708                 eval ppo=\${sp_dir_${suitename}[num]}
709                 IFS=,; set -o noglob
710                 set -A pva -- $pvo
711                 set -A ppa -- $ppo
712                 IFS=$' \t\n'; set +o noglob
713                 (( ${#pva[*]} )) || pva[0]=
714                 y=
715                 i=0
716                 while (( i < ${#pva[*]} )); do
717                         pv=${pva[i]}
718                         pp=${ppa[i]}
719                         if [[ $pv = *"\1a"* ]]; then
720                                 pvdsc=${pv%%"\1a"*}
721                                 pv=${pv##*"\1a"}
722                         else
723                                 pvdsc=$pv
724                         fi
725                         if [[ -z $pv ]]; then
726                                 pv=-
727                                 if (( nrpl )); then
728                                         x=${suitename}/${sp_dist[num]}/${sp_name[num]}/%
729                                         j=0
730                                         while (( j < nrpl )); do
731                                                 [[ ${preplsrc[j]} = "$x" ]] && break
732                                                 let j++
733                                         done
734                                         (( j < nrpl )) && pv=${prepldst[j]}
735                                 fi
736                         elif [[ $pp != ?(/) ]]; then
737                                 pv="<a href=\"$pp${sp_name[num]}_${pvdsc##+([0-9]):}.dsc\">$pv</a>"
738                         fi
739                         [[ $pp != ?(/) ]] && pv="<a href=\"$pp\">[dir]</a> $pv"
740                         y=${y:+"$y<br />"}$pv
741                         let i++
742                 done
743                 print " <td rowspan=\"2\" class=\"srcpkgitem\">$y</td>"
744         done
745         print "</tr><tr class=\"srcpkgline\">"
746         print " <td class=\"srcpkgname\">${sp_name[num]}</td>"
747         print "</tr>"
748         k=0
749         while (( k < nbin )); do
750                 (( (i = bp_sort[k++]) < 0 )) && continue
751                 [[ ${bp_name[i]} = "${sp_name[num]}" && \
752                     ${bp_dist[i]} = "${sp_dist[num]}" ]] || continue
753                 bp_sort[k - 1]=-1
754                 #print "<!-- bp #$i for${bp_suites[i]} -->"
755                 print "<!-- bp #$i -->"
756                 print "<tr class=\"binpkgline\">"
757                 print " <td class=\"binpkgname\">${bp_disp[i]}</td>"
758                 print " <td class=\"binpkgdesc\">$(xhtml_escape "${bp_desc[i]}")</td>"
759                 for suitename in $allsuites; do
760                         [[ -h dists/$suitename ]] && continue
761                         eval pv=\${bp_ver_${suitename}[i]}
762                         if [[ -z $pv ]]; then
763                                 pv=-
764                                 if (( nrpl )); then
765                                         x=${suitename}/${sp_dist[num]}/${sp_name[num]}/%
766                                         j=0
767                                         while (( j < nrpl )); do
768                                                 [[ ${preplsrc[j]} = "$x" ]] && break
769                                                 let j++
770                                         done
771                                         (( j < nrpl )) && pv=${prepldst[j]}
772                                 fi
773                         fi
774                         print " <td class=\"binpkgitem\">$pv</td>"
775                 done
776                 print "</tr>"
777         done
778 done
779
780 num=0
781 for i in ${bp_sort[*]}; do
782         (( i < 0 )) && continue
783         if (( !num )); then
784                 print "\n<!-- sp ENOENT -->"
785                 print "<tr class=\"srcpkgline\">"
786                 print " <td class=\"srcpkgname\">~ENOENT~</td>"
787                 print " <td class=\"srcpkgdesc\">binary" \
788                     "packages without a matching source package</td>"
789                 for suitename in $allsuites; do
790                         [[ -h dists/$suitename ]] && continue
791                         print " <td class=\"srcpkgitem\">-</td>"
792                 done
793                 print "</tr>"
794                 num=1
795         fi
796         #print "<!-- bp #$i for${bp_suites[i]} -->"
797         print "<!-- bp #$i -->"
798         print "<tr class=\"binpkgline\">"
799         print " <td class=\"binpkgdist\">${bp_dist[i]}</td>"
800         print " <td rowspan=\"2\" class=\"binpkgdesc\">$(xhtml_escape "${bp_desc[i]}")</td>"
801         for suitename in $allsuites; do
802                 [[ -h dists/$suitename ]] && continue
803                 eval pv=\${bp_ver_${suitename}[i]}
804                 if [[ -z $pv ]]; then
805                         pv=-
806                         if (( nrpl )); then
807                                 x=${suitename}/${bp_dist[num]}/${bp_disp[num]}/=
808                                 j=0
809                                 while (( j < nrpl )); do
810                                         [[ ${preplsrc[j]} = "$x" ]] && break
811                                         let j++
812                                 done
813                                 (( j < nrpl )) && pv=${prepldst[j]}
814                         fi
815                 fi
816                 print " <td rowspan=\"2\" class=\"binpkgitem\">$pv</td>"
817         done
818         print "</tr><tr class=\"binpkgline\">"
819         print " <td class=\"binpkgname\">${bp_disp[i]}</td>"
820         print "</tr>"
821 done
822
823 cat <<EOF
824
825 </tbody></table>
826
827 <p>• <a href="http://validator.w3.org/check/referer">Valid XHTML/1.1!</a>
828  • <small>Generated on $(date -u +'%F %T') by <tt
829  style="white-space:pre;">$rcsid</tt></small> •</p>
830 </body></html>
831 EOF
832
833 :) >debidx.htm
834 print done.