さきに作ったカレンダープログラムでは、サブルーチンとパラメータのやりとりをしないで、サブルーチンでグローバル変数を書き換えるようにしました。しかし、メインルーチンとパラメータのやりとりをきちんとしておけば、サブルーチンをモジュール化できて、他のプログラムでも使うことができるので、正式な方法でサブルーチンとパラメータをやりとりするようにしてみました。
パラメータは、&find_first_last($year, $month) というように()でくくってサブルーチンに渡します。サブルーチンのほうでは、これを @_ という特別な配列で受け取りますので、$year, $month は次のようにして受け取ります。
$year = $_[0]; $month = $_[1];この時、メインルーチンとサブルーチンのパラメータの個数や、順序を間違えないように気をつけましょう。 サブルーチンから、価を返すには、価が一個なら return $value; で済みますが、二個以上の場合は、次のように、配列に入れて返します。
$return_value[0] = $first_day; $return_value[1] = $last_date; return @return_value;これは次のように書くこともできます。
return ($first_day, $last_date);これを受け取るには、メインルーチンに用意した変数に代入するだけです。配列で受け取った時は、次のように個々の変数に価をいれておきます。
@find_value = &find_first_last($year, $month); $first_day = $find_value[0]; $last_date = $find_value[1];これも次のように書くことができます。
($first_day, $last_date) = &find_first_last($year, $month);
このような要領で書き換えたメインルーチンは次の通りです。
#!/usr/bin/perl # # calendar02.pl # if($ARGV[0] eq ""){ print "Input year and month.\n"; exit(0); } if($ARGV[1] eq ""){ @parameters = split /\D/, $ARGV[0]; if($parameters[1] eq ""){ print "Input year and month.\n"; exit(0); } else{ $year = $parameters[0]; $month = $parameters[1]; } } else{ $year = $ARGV[0]; $month = $ARGV[1]; } if($month < 1 or $month > 12){ print "Month is out of range.\n"; exit(0); } ($first_day, $last_day) = &find_first_last($year, $month); &show_a_month($year, $month, $first_day, $last_date); exit(0);
日数計算のサブルーチンでは、サブルーチンで使う変数をすべてローカルにするために locoal () を使って、一度に定義してしまいました。結果は次の通りです。
sub find_first_last(){ local($year, $month, @month_days, $days, $i, $first_day, $last_day, @return_value); ($year, $month) = @_; @month_days = (0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31); if(($year % 4) == 0 and ($year % 100) != 0 or ($year % 400) == 0) { $month_days[2] = 29; } $days = $year + int(($year-1)/4) - int(($year-1)/100) + int(($year-1)/400); $i = 0; while($i < $month){ $days += $month_days[$i]; $i++; } $first_day = $days % 7; $last_date = $month_days[$month]; return ($first_day, $last_day); }
カレンダーを表示するサブルーチンでは、月の表示を、数字でなく、名前で行うため
@month_name = ("", "January", "Feburary", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December");という配列を用意しました。月は1月から始まるので、配列の 0番目はブランクにしてあります。文字列配列は次のように書くこともでき、この場合は " (引用符) はいりませんし、区切りは , (カンマ) でなく、スペースになります。
@month_name = qw(dummy January Feburary March April May June July August September October November December);この書き方では、0月を一応 dummy としておきました。次は書き換えたサブルーチンです。
sub show_a_month(){ local (@month_name, $year, $month, $i, $date, $first_day, $last_date); ($year, $month, $first_day, $last_day) = @_; @month_name = ("", "January", "Feburary", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"); print " $month_name[$month], $year\n"; print " Su Mo Tu We Th Fr Sa\n"; $i = 0; while($i < $first_day){ print " "; $i++; } $date = 1; while($date <= $last_date){ print " "; if ($date < 10){ print " "; } print $date; if(($first_day + $date -1) % 7 == 6){ print "\n"; } $date++; } print "\n"; }