[BACK]Return to tzselect.ksh CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / lib / libc / time

Annotation of src/lib/libc/time/tzselect.ksh, Revision 1.1.1.2

1.1       jtc         1: #! /bin/ksh
                      2: # Ask the user about the time zone, and output the resulting TZ value to stdout.
                      3: # Interact with the user via stderr and stdin.
                      4:
                      5: # Contributed by Paul Eggert <eggert@twinsun.com>.
                      6:
                      7: # Porting notes:
                      8: #
                      9: # This script requires several features of the Korn shell.
                     10: # If your host lacks the Korn shell,
                     11: # you can use either of the following free programs instead:
                     12: #
                     13: #      Bourne-Again shell (bash)
1.1.1.2 ! jtc        14: #      <URL:ftp://ftp.gnu.ai.mit.edu/pub/gnu/>
1.1       jtc        15: #
                     16: #      Public domain ksh
1.1.1.2 ! jtc        17: #      <URL:ftp://ftp.cs.mun.ca/pub/pdksh/pdksh.tar.gz>
1.1       jtc        18: #
                     19: # This script also uses several features of modern awk programs.
                     20: # If your host lacks awk, or has an old awk that does not conform to Posix.2,
                     21: # you can use either of the following free programs instead:
                     22: #
                     23: #      GNU awk (gawk)
1.1.1.2 ! jtc        24: #      <URL:ftp://ftp.gnu.ai.mit.edu/pub/gnu/>
1.1       jtc        25: #
                     26: #      mawk
1.1.1.2 ! jtc        27: #      <URL:ftp://ftp.whidbey.net/pub/brennan/>
1.1       jtc        28:
                     29:
                     30: # Specify default values for environment variables if they are unset.
                     31: : ${AWK=awk}
                     32: : ${TZDIR=$(pwd)}
                     33:
                     34: # Check for awk Posix compliance.
                     35: ($AWK -v x=y 'BEGIN { exit 123 }') </dev/null >/dev/null 2>&1
                     36: [ $? = 123 ] || {
                     37:        echo >&2 "$0: Sorry, your \`$AWK' program is not Posix compatible."
                     38:        exit 1
                     39: }
                     40:
                     41: # Make sure the tables are readable.
                     42: TZ_COUNTRY_TABLE=$TZDIR/iso3166.tab
                     43: TZ_ZONE_TABLE=$TZDIR/zone.tab
                     44: for f in $TZ_COUNTRY_TABLE $TZ_ZONE_TABLE
                     45: do
                     46:        <$f || {
                     47:                echo >&2 "$0: time zone files are not set up correctly"
                     48:                exit 1
                     49:        }
                     50: done
                     51:
                     52: newline='
                     53: '
                     54: IFS=$newline
                     55:
                     56:
1.1.1.2 ! jtc        57: # Work around a bug in bash 1.14.7 and earlier, where $PS3 is sent to stdout.
1.1       jtc        58: case $(echo 1 | (select x in x; do break; done) 2>/dev/null) in
                     59: ?*) PS3=
                     60: esac
                     61:
                     62:
                     63: # Begin the main loop.  We come back here if the user wants to retry.
                     64: while
                     65:
                     66:        echo >&2 'Please identify a location' \
                     67:                'so that time zone rules can be set correctly.'
                     68:
                     69:        continent=
                     70:        country=
                     71:        region=
                     72:
                     73:
                     74:        # Ask the user for continent or ocean.
                     75:
                     76:        echo >&2 'Please select a continent or ocean.'
                     77:
                     78:        select continent in \
                     79:            Africa \
                     80:            Americas \
                     81:            Antarctica \
                     82:            'Arctic Ocean' \
                     83:            Asia \
                     84:            'Atlantic Ocean' \
                     85:            Australia \
                     86:            Europe \
                     87:            'Indian Ocean' \
                     88:            'Pacific Ocean' \
                     89:            'none - I want to specify the time zone using the Posix TZ format.'
                     90:        do
                     91:            case $continent in
                     92:            '')
                     93:                echo >&2 'Please enter a number in range.';;
                     94:            ?*)
                     95:                case $continent in
                     96:                Americas) continent=America;;
                     97:                *' '*) continent=$(expr "$continent" : '\([^ ]*\)')
                     98:                esac
                     99:                break
                    100:            esac
                    101:        done
                    102:        case $continent in
                    103:        '')
                    104:                exit 1;;
                    105:        none)
                    106:                # Ask the user for a Posix TZ string.  Check that it conforms.
                    107:                while
                    108:                        echo >&2 'Please enter the desired value' \
                    109:                                'of the TZ environment variable.'
                    110:                        echo >&2 'For example, GST-10 is a zone named GST' \
                    111:                                'that is 10 hours ahead (east) of UTC.'
                    112:                        read TZ
                    113:                        $AWK -v TZ="$TZ" 'BEGIN {
                    114:                                tzname = "[^-+,0-9][^-+,0-9][^-+,0-9]+"
                    115:                                time = "[0-2]?[0-9](:[0-5][0-9](:[0-5][0-9])?)?"
                    116:                                offset = "[-+]?" time
                    117:                                date = "(J?[0-9]+|M[0-9]+\.[0-9]+\.[0-9]+)"
                    118:                                datetime = "," date "(/" time ")?"
                    119:                                tzpattern = "^(:.*|" tzname offset "(" tzname \
                    120:                                  "(" offset ")?(" datetime datetime ")?)?)$"
                    121:                                if (TZ ~ tzpattern) exit 1
                    122:                                exit 0
                    123:                        }'
                    124:                do
                    125:                        echo >&2 "\`$TZ' is not a conforming" \
                    126:                                'Posix time zone string.'
                    127:                done
                    128:                TZ_for_date=$TZ;;
                    129:        *)
                    130:                # Get list of names of countries in the continent or ocean.
                    131:                countries=$($AWK -F'\t' \
                    132:                        -v continent="$continent" \
                    133:                        -v TZ_COUNTRY_TABLE="$TZ_COUNTRY_TABLE" \
                    134:                '
                    135:                        /^#/ { next }
                    136:                        $3 ~ ("^" continent "/") {
                    137:                                if (!cc_seen[$1]++) cc_list[++ccs] = $1
                    138:                        }
                    139:                        END {
                    140:                                while (getline <TZ_COUNTRY_TABLE) {
                    141:                                        if ($0 !~ /^#/) cc_name[$1] = $2
                    142:                                }
                    143:                                for (i = 1; i <= ccs; i++) {
                    144:                                        country = cc_list[i]
                    145:                                        if (cc_name[country]) {
                    146:                                          country = cc_name[country]
                    147:                                        }
                    148:                                        print country
                    149:                                }
                    150:                        }
                    151:                ' <$TZ_ZONE_TABLE | sort -f)
                    152:
                    153:
                    154:                # If there's more than one country, ask the user which one.
                    155:                case $countries in
                    156:                *"$newline"*)
                    157:                        echo >&2 'Please select a country.'
                    158:                        select country in $countries
                    159:                        do
                    160:                            case $country in
                    161:                            '') echo >&2 'Please enter a number in range.';;
                    162:                            ?*) break
                    163:                            esac
                    164:                        done
                    165:
                    166:                        case $country in
                    167:                        '') exit 1
                    168:                        esac;;
                    169:                *)
                    170:                        country=$countries
                    171:                esac
                    172:
                    173:
                    174:                # Get list of names of time zone rule regions in the country.
                    175:                regions=$($AWK -F'\t' \
                    176:                        -v country="$country" \
                    177:                        -v TZ_COUNTRY_TABLE="$TZ_COUNTRY_TABLE" \
                    178:                '
                    179:                        BEGIN {
                    180:                                cc = country
                    181:                                while (getline <TZ_COUNTRY_TABLE) {
                    182:                                        if ($0 !~ /^#/  &&  country == $2) {
                    183:                                                cc = $1
                    184:                                                break
                    185:                                        }
                    186:                                }
                    187:                        }
                    188:                        $1 == cc { print $4 }
                    189:                ' <$TZ_ZONE_TABLE)
                    190:
                    191:
                    192:                # If there's more than one region, ask the user which one.
                    193:                case $regions in
                    194:                *"$newline"*)
                    195:                        echo >&2 'Please select one of the following' \
                    196:                                'time zone regions.'
                    197:                        select region in $regions
                    198:                        do
                    199:                                case $region in
                    200:                                '') echo >&2 'Please enter a number in range.';;
                    201:                                ?*) break
                    202:                                esac
                    203:                        done
                    204:                        case $region in
                    205:                        '') exit 1
                    206:                        esac;;
                    207:                *)
                    208:                        region=$regions
                    209:                esac
                    210:
                    211:                # Determine TZ from country and region.
                    212:                TZ=$($AWK -F'\t' \
                    213:                        -v country="$country" \
                    214:                        -v region="$region" \
                    215:                        -v TZ_COUNTRY_TABLE="$TZ_COUNTRY_TABLE" \
                    216:                '
                    217:                        BEGIN {
                    218:                                cc = country
                    219:                                while (getline <TZ_COUNTRY_TABLE) {
                    220:                                        if ($0 !~ /^#/  &&  country == $2) {
                    221:                                                cc = $1
                    222:                                                break
                    223:                                        }
                    224:                                }
                    225:                        }
                    226:                        $1 == cc && $4 == region { print $3 }
                    227:                ' <$TZ_ZONE_TABLE)
                    228:
                    229:                # Make sure the corresponding zoneinfo file exists.
                    230:                TZ_for_date=$TZDIR/$TZ
                    231:                <$TZ_for_date || {
                    232:                        echo >&2 "$0: time zone files are not set up correctly"
                    233:                        exit 1
                    234:                }
                    235:        esac
                    236:
                    237:
                    238:        # Use the proposed TZ to output the current date relative to UTC.
                    239:        # Loop until they agree in seconds.
                    240:        # Give up after 8 unsuccessful tries.
                    241:
                    242:        extra_info=
                    243:        for i in 1 2 3 4 5 6 7 8
                    244:        do
                    245:                TZdate=$(LANG=C TZ="$TZ_for_date" date)
                    246:                UTdate=$(LANG=C TZ=UTC0 date)
                    247:                TZsec=$(expr "$TZdate" : '.*:\([0-5][0-9]\)')
                    248:                UTsec=$(expr "$UTdate" : '.*:\([0-5][0-9]\)')
                    249:                case $TZsec in
                    250:                $UTsec)
                    251:                        extra_info="
                    252: Local time is now:     $TZdate.
                    253: Universal Time is now: $UTdate."
                    254:                        break
                    255:                esac
                    256:        done
                    257:
                    258:
                    259:        # Output TZ info and ask the user to confirm.
                    260:
                    261:        echo >&2 ""
                    262:        echo >&2 "The following information has been given:"
                    263:        echo >&2 ""
                    264:        case $country+$region in
                    265:        ?*+?*)  echo >&2 "      $country$newline        $region";;
                    266:        ?*+)    echo >&2 "      $country";;
                    267:        +)      echo >&2 "      TZ='$TZ'"
                    268:        esac
                    269:        echo >&2 ""
                    270:        echo >&2 "Therefore TZ='$TZ' will be used.$extra_info"
                    271:        echo >&2 "Is the above information OK?"
                    272:
                    273:        ok=
                    274:        select ok in Yes No
                    275:        do
                    276:            case $ok in
                    277:            '') echo >&2 'Please enter 1 for Yes, or 2 for No.';;
                    278:            ?*) break
                    279:            esac
                    280:        done
                    281:        case $ok in
                    282:        '') exit 1;;
                    283:        Yes) break
                    284:        esac
                    285: do :
                    286: done
                    287:
                    288: # Output the answer.
                    289: echo "$TZ"

CVSweb <webmaster@jp.NetBSD.org>