home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / qtawk / calcrpna.exp < prev    next >
Text File  |  1990-11-09  |  19KB  |  617 lines

  1. # calcrp - reverse-Polish calculator
  2. #
  3. # Reverse Polish Calculator.
  4. # (C) Copyright 1989, 1990 Terry D. Boldt, All Rights Reserved.
  5. #
  6. # input: expression in reverse polish
  7. # output: value of each expression
  8. #
  9. BEGIN {
  10.     month_array[ 1] = "January";
  11.     month_array[ 2] = "February";
  12.     month_array[ 3] = "March";
  13.     month_array[ 4] = "April";
  14.     month_array[ 5] = "May";
  15.     month_array[ 6] = "June";
  16.     month_array[ 7] = "July";
  17.     month_array[ 8] = "August";
  18.     month_array[ 9] = "September";
  19.     month_array[10] = "October";
  20.     month_array[11] = "November";
  21.     month_array[12] = "December";
  22.     week_day[0] = "Sunday";
  23.     week_day[1] = "Monday";
  24.     week_day[2] = "Tuesday";
  25.     week_day[3] = "Wednesday";
  26.     week_day[4] = "Thursday";
  27.     week_day[5] = "Friday";
  28.     week_day[6] = "Saturday";
  29.     number = /^({_i}|{_f}({_e})?)$/;    # integer & floating point numbers
  30.     variable_set = /^[a-zA-Z_][a-zA-Z0-9]*=$/;     # variable name set
  31.     variable_del = /^[a-zA-Z_][a-zA-Z0-9]*-$/;     # variable name delete
  32.     vars["pi"] = pi;    # built-in variable
  33.     vars["e"] = exp(1); # built-in variable
  34.     rtd = 180/pi;    # constant to convert radians to degrees
  35.     cm_inch = 2.54;    # centimeters / inch (exact)
  36.     km_sm = 1.609344;    # kilometers / mile  (exact)
  37.     Lts_gal = 3.785411784;# Liters / gallon (U.S. liquid)
  38.     stderr = "stderr";
  39.     prt_ln = "%s\n";
  40. #
  41. # Gregorian/Julian calender flag.
  42. #   TRUE == julian
  43. #   FALSE == gregorian
  44. #
  45.     greg_jul = FALSE;
  46.     split(sdate(1),tdate,/\//);
  47.     vars["today"] = jdn(tdate[3],tdate[1],tdate[2]);
  48.  
  49.     Yess = /[Yy](es)?/;           # Yes string
  50.     Nos  = /[Nn]o?/;              # No  string
  51.     Yes  = /^{_w}*{Yess}{_w}*$/;      # Yes answer
  52.     No     = /^{_w}*{Nos}{_w}*$/;       # No  answer
  53.     Quit = /^{_w}*[Qq](uit)?({_w}+({Yess}|{Nos}))?{_w}*$/;  # define regular expression To  Quit
  54.     Help = /^{_w}*[Hh](elp)?{_w}*$/;    # define regular expression for Help
  55.     Stat = /^{_w}*[Ss](tat)?{_w}*$/;    # define regular expression for Stats
  56.     Cls  = /^{_w}*[Cc](ls)?{_w}*$/;    # define regular expression To Clear Screen
  57.  
  58.     quit_status = TRUE;
  59.  
  60.     copyright;
  61.     prompt;
  62. }
  63.  
  64. GROUP Quit {
  65.     if ( NF > 1 ) {
  66.     switch ( $2 ) {
  67.         case Yes:
  68.         quit_status = TRUE;
  69.         break;
  70.         case No:
  71.         quit_status = FALSE;
  72.         break;
  73.     }
  74.     }
  75.     exit 2;
  76. }
  77.  
  78. GROUP Help { help; prompt; next; }
  79.  
  80. GROUP Stat { stat; prompt; next; }
  81.  
  82. GROUP Cls  { copyright; prompt; next; }
  83.  
  84.     {
  85.     local ivar, ntime, dte;
  86.  
  87.     for ( i = 1 ; i <= NF ; i++ ) {
  88.     if ( $i ~~ number ) {    # find numbers
  89.         stack[++top] = $i + 0.0; # force numbers to real by adding 0.0
  90.       } else if ( j = mono_operation($i) ) {   # built-in mono operator ?
  91.         j;    # do nothing statement
  92.       } else if ( j = binary_operation($i) ) { # built-in binary operator ?
  93.         top--;
  94.       } else if ( j = tern_operation($i) ) { # built ternary operator ?
  95.         top -= 2;
  96.       } else if ( $i == "pmonth" ) { # set stack top to current time
  97.         dte = caln(today);
  98.         three_month(dte[1],dte[2],dte[3]);
  99.       } else if ( $i == "now" ) { # set stack top to current time
  100.         split(stime(1),ntime,/:/);
  101.         stack[++top] = hrs(ntime[1] + 0.0,ntime[2] + 0.0,ntime[3] + 0.0);
  102.       } else if ( $i == "deg" ) { # use degrees in trig
  103.         DEGREES = TRUE;   # set built-in variable
  104.       } else if ( $i == "rad" ) { # use radians in trig - start-up default
  105.         DEGREES = FALSE;  # set built-in variable
  106.       } else if ( $i == "greg" ) { # toggle gregorian/julian calender
  107.         greg_jul = !greg_jul;
  108.         printf("Calender Set: %s.\n",greg_jul ? "Julian" : "Gregorian");
  109.       } else if ( $i in vars ) { # defined variable ?
  110.         stack[++top] = vars[$i];
  111.       } else if ( $i ~~ variable_set && top > 0 ) { # variable definition ?
  112.         # NOTE: for single letter variable names,
  113.         # substr($i,1,length($i)-1)
  114.         # returns a single letter and not a string. The single letter
  115.         # is interpreted by the subscripting routine as a numeric
  116.         # and gives 'strange' subscripts. To prevent, concatenate
  117.         # a null string on substr return to force to a string irregardless
  118.         vars[substr($i,1,length($i)-1) ∩ ""] = stack[top--];
  119.       } else if ( $i ~~ variable_del ) { # variable deletion ?
  120.         # Again force substr return to a string
  121.         ivar = substr($i,1,length($i)-1) ∩ "";
  122.         if ( ivar in vars ) delete vars[ivar];
  123.           else printf("error: attempt to delete ivar - non-existent.\n");
  124.       } else { # unknown operation
  125.         printf("error: cannot evaluate %s\n",$i);
  126.         top = 0;
  127.         prompt;
  128.         next;
  129.     }
  130.     }
  131.     if ( top == 1 && $NF !~ /^=$/ ) {
  132.     ostr = addcomma(stack[top--]);
  133.     print "\t" ostr;
  134.       } else if ( top > 1 ) {
  135.     printf("error: too many operands\n");
  136.     top = 0;
  137.     }
  138.     prompt;
  139. }
  140.  
  141. END {
  142.     if ( quit_status ) copyright;
  143. }
  144.  
  145. # function to find binary operations - needs two numbers
  146. function binary_operation(op) {
  147.     local ret = FALSE;    # return value - assume no match
  148.     local swap;
  149.  
  150.     if ( top > 1 ) switch ( op ) {
  151.     case '+':   # addition
  152.         stack[top-1] += stack[top];
  153.         ret = 1;
  154.         break;
  155.     case '-':   # subtraction
  156.         stack[top-1] -= stack[top];
  157.         ret = 2;
  158.         break;
  159.     case '*':   # multiplication
  160.         stack[top-1] *= stack[top];
  161.         ret = 3;
  162.         break;
  163.     case '/':   # division
  164.         stack[top-1] /= stack[top];
  165.         ret = 4;
  166.         break;
  167.     case '^':   # exponentiation
  168.         stack[top-1] ^= stack[top];
  169.         ret = 5;
  170.         break;
  171.     case '&':   # binary and
  172.         stack[top-1] &= stack[top];
  173.         ret = 6;
  174.         break;
  175.     case '|':   # binary or
  176.         stack[top-1] |= stack[top];
  177.         ret = 7;
  178.         break;
  179.     case '@':   # binary xor
  180.         stack[top-1] @= stack[top];
  181.         ret = 8;
  182.         break;
  183.     case '%':   # modulus
  184.         stack[top-1] %= stack[top];
  185.         ret = 9;
  186.         break;
  187.     case ">>":   # shift right
  188.         stack[top-1] >>= stack[top];
  189.         ret = 10;
  190.         break;
  191.     case "<<":   # shift left
  192.         stack[top-1] <<= stack[top];
  193.         ret = 11;
  194.         break;
  195.     case "swap": # swap top two stack numbers
  196.         swap = stack[top];
  197.         stack[top] = stack[top-1];
  198.         stack[top-1] = swap;
  199.         top++;  # compensate for reduction upon return
  200.         ret = 12;
  201.         break;
  202.     case "atan2":
  203.         stack[top-1] = atan2(stack[top-1],stack[top]);
  204.         ret = 13;
  205.         break;
  206.     case "calm":
  207.         three_month(int(stack[top-1]),int(stack[top]),0);
  208.         top--;
  209.         ret = 14;
  210.         break;
  211.     }
  212.     return ret;
  213. }
  214.  
  215. # function to recognize mono operations - require only one number
  216. function mono_operation(fun) {
  217.     local ret = FALSE;    #return value - assume no match
  218.     local stck = FALSE;
  219.  
  220.     if ( top ) switch ( fun ) {
  221.     case "sin":
  222.         stack[top] = sin(stack[top]);
  223.         ret = 100;
  224.         break;
  225.     case "asin":
  226.         stack[top] = asin(stack[top]);
  227.         ret = 100;
  228.         break;
  229.     case "cos":
  230.         stack[top] = cos(stack[top]);
  231.         ret = 101;
  232.         break;
  233.     case "acos":
  234.         stack[top] = acos(stack[top]);
  235.         ret = 101;
  236.         break;
  237.     case "sinh":
  238.         stack[top] = sinh(stack[top]);
  239.         ret = 117;
  240.         break;
  241.     case "cosh":
  242.         stack[top] = cosh(stack[top]);
  243.         ret = 118;
  244.         break;
  245.     case "log":
  246.         stack[top] = log(stack[top]);
  247.         ret = 102;
  248.         break;
  249.     case "log10":
  250.         stack[top] = log10(stack[top]);
  251.         ret = 102;
  252.         break;
  253.     case "int":
  254.         stack[top] = int(stack[top]);
  255.         ret = 103;
  256.         break;
  257.     case "exp":
  258.         stack[top] = exp(stack[top]);
  259.         ret = 104;
  260.         break;
  261.     case "sqrt":
  262.         stack[top] = sqrt(stack[top]);
  263.         ret = 105;
  264.         break;
  265.     case "fract":
  266.         stack[top] = fract(stack[top]);
  267.         ret = 106;
  268.         break;
  269.     case "push":
  270.         stack[top+1] = stack[top];
  271.         top++;
  272.         ret = 107;
  273.         break;
  274.     case "pop":
  275.         top--;
  276.         ret = 108;
  277.         break;
  278.     case "=": # display top of stack
  279.         printf("\t%d: %s\n",top,addcomma(stack[top]));
  280.         ret = 109;
  281.         break;
  282.     case "=s": # display entire stack
  283.         for ( stck in stack ) printf("\t%d: %s\n",stck,addcomma(stack[stck]));
  284.         ret = 118;
  285.         break;
  286.     case '~':   # ones complement
  287.         stack[top] = ~stack[top];
  288.         ret = 110;
  289.         break;
  290.     case /^\+\/?-$/:   # change sign of stack top
  291.     case /^-\/?\+$/:   # change sign of stack top
  292.         stack[top] = -stack[top];
  293.         ret = 117;
  294.         break;
  295.     case "rtd": # convert radians to degrees
  296.         stack[top] = stack[top] * rtd;
  297.         ret = 111;
  298.         break;
  299.     case "dtr": # convert degrees to radians
  300.         stack[top] = stack[top] / rtd;
  301.         ret = 112;
  302.         break;
  303.     case "cti": # convert centimeters to inches
  304.         stack[top] = stack[top] / cm_inch;
  305.         ret = 113;
  306.         break;
  307.     case "itc": # convert inches to centimeters
  308.         stack[top] = stack[top] * cm_inch;
  309.         ret = 114;
  310.         break;
  311.     case "ktm": # convert kilometers to miles
  312.         stack[top] = stack[top] / km_sm;
  313.         ret = 114;
  314.         break;
  315.     case "mtk": # convert miles to kilometers
  316.         stack[top] = stack[top] * km_sm;
  317.         ret = 114;
  318.         break;
  319.     case "ltg": # convert Liters to gallons
  320.         stack[top] = stack[top] /Lts_gal;
  321.         ret = 114;
  322.         break;
  323.     case "gtl": # convert gallons to Liters
  324.         stack[top] = stack[top] * Lts_gal;
  325.         ret = 114;
  326.         break;
  327.     case "cals": # convert stack top from julian day number to date
  328.              # leave result on stack
  329.         stck = TRUE;
  330.     case "cal":  # convert stack top from julian day number to date
  331.         ret = (stack[top] + 1) % 7;
  332.         stack_date(stack[top]);
  333.         printf("\tyr: %2u\n",stack[top-2]);
  334.         printf("\tmo: %2u (%s)\n",stack[top-1],month_array[stack[top-1]]);
  335.         printf("\tdy: %2u (%s)\n",stack[top],week_day[ret]);
  336.         if ( !stck ) top -= 3;
  337.         ret = 115;
  338.         break;
  339.     case "hmss": # convert stack top from hrs to hrs, minutes, seconds
  340.              # leave result on stack
  341.         stck = TRUE;
  342.     case "hms":  # convert stack top from hrs to hrs, minutes, seconds
  343.         hms(stack[top]);
  344.         printf("\thr: %2g",stack[top-2]);
  345.         if ( stack[top-2] > 12 ) printf(" (%2u pm)",stack[top-2] - 12);
  346.         printf("\n");
  347.         printf("\tmn: %2g\n",stack[top-1]);
  348.         printf("\tsc: %2g\n",stack[top]);
  349.         if ( !stck ) top -= 3;
  350.         ret = 116;
  351.         break;
  352.     case "fdates": # compute date for stack[top] days in future (past)
  353.                # leave result on stack
  354.         stck = TRUE;
  355.     case "fdate":  # compute date for stack[top] days in future (past)
  356.         ret = fdate(stack[top]);
  357.         printf("\tyr: %2u\n",stack[top-2]);
  358.         printf("\tmo: %2u (%s)\n",stack[top-1],month_array[stack[top-1]]);
  359.         printf("\tdy: %2u (%s)\n",stack[top],week_day[ret]);
  360.         if ( !stck ) top -= 3;
  361.         ret = 117;
  362.         break;
  363.     }
  364.     return ret;
  365. }
  366.  
  367. # function to recognize ternary operations - require three numbers
  368. function tern_operation(fun) {
  369.     local ret = FALSE;    #return value - assume no match
  370.  
  371.     if ( top > 2 ) switch ( fun ) {
  372.     case "jdn":
  373.         stack[top-2] = jdn(stack[top-2],stack[top-1],stack[top]);
  374.         ret = 300;
  375.         break;
  376.     case "hrs":
  377.         stack[top-2] = hrs(stack[top-2],stack[top-1],stack[top]);
  378.         ret = 301;
  379.         break;
  380.     case "dow":
  381.         stack[top-2] = day_of_week(stack[top-2],stack[top-1],stack[top]);
  382.         ret = 302;
  383.         break;
  384.     case "calmh":
  385.         three_month(int(stack[top-2]),int(stack[top-1]),int(stack[top]));
  386.         top--;
  387.         ret = 303;
  388.         break;
  389.     }
  390.     return ret;
  391. }
  392.  
  393. # function to convert year/month/day into julian day number
  394. function jdn(year,month,day) {
  395.     local yr;
  396.     local pfac = 0.6;
  397.     local ljdn;
  398.  
  399.     yr = year + (month - 3.0) / 12.0;
  400.     ljdn = int(367.0 * yr + pfac) - (2 * int(yr)) + int(yr/4.0)
  401.        + int(day) + 1721117;
  402.     if ( !greg_jul ) ljdn += -int(yr/100.0) + int(yr/400.0) + 2;
  403.     return ljdn;
  404. }
  405.  
  406. #  function to convert julian dday number to year/month/day
  407. function caln(cjdn) {
  408.     local n, ic, np, npp, mp;
  409.     local yr, mo, day;
  410.     local dte; # dte[1] == year, dte[2] == month, dte[3] == day
  411.  
  412.     n = int(cjdn) - 1721119;
  413.     ic = int((n - 0.2)/36524.25);
  414.     if ( greg_jul ) np = n + 2; else np = n + ic - (ic / 4);
  415.     yr = int((np - 0.2)/365.25);
  416.     npp = np - int(365.25 * yr);
  417.     mp = int((npp - 0.5)/30.6);
  418.     day = int(npp + 0.5 - 30.6 * mp);
  419.     if ( mp <= 9 ) mo = mp + 3;
  420.       else {
  421.     yr++;
  422.     mo = mp - 9;
  423.     }
  424.     dte[1] = yr;
  425.     dte[2] = mo;
  426.     dte[3] = day;
  427.     return dte; # return date ARRAY
  428. }
  429.  
  430. # function to set date corresponding to julian day number passed into stack
  431. # stack[top - 2] == year
  432. # stack[top - 1] == month
  433. # stack[top]     == day
  434. function stack_date(cjdn) {
  435.     local dte;
  436.  
  437.     dte = caln(cjdn);
  438.     stack[top]       = dte[1]; # year
  439.     stack[top + 1] = dte[2]; # month
  440.     stack[top + 2] = dte[3]; # day
  441.     top += 2;
  442. }
  443.  
  444. # function to set stack to today + days in future (past)
  445. function fdate(days) {
  446.     local fd;
  447.     local wkday;
  448.  
  449.     fd = vars["today"] + days;
  450.     wkday = (fd + 1) % 7;
  451.     stack_date(fd);
  452.     return wkday;
  453. }
  454.  
  455. # function to convert hours, minutes, seconds to fractional hours
  456. function hrs(hrs,min,sec) {
  457.     return hrs += min/60 + sec/3600;
  458. }
  459.  
  460. # functions to convert fractional hours to hrs, min, sec
  461. function hms(hrs) {
  462.     local mins = fract(hrs) * 60;
  463.     local secs = fract(mins) * 60;
  464.  
  465.     stack[top] = int(hrs);
  466.     stack[top+1] = int(mins);
  467.     stack[top+2] = secs = secs > 1 ? secs : 0;
  468.     if ( secs > 59 ) {
  469.     stack[top+1]++;
  470.     stack[top+2] = 0;
  471.     } else stack[top+2] = int(secs);
  472.     top += 2;
  473. }
  474.  
  475. # function to provide header & copyright information
  476. function copyright() {
  477.     cls;
  478.     fprintf(stderr,prt_ln,"");
  479.     fprintf(stderr,prt_ln,"Reverse Polish Calculator.\n(C) Copyright 1989, 1990 Terry D. Boldt, All Rights Reserved.");
  480. }
  481.  
  482. # function to provide help - list operators and functions
  483. function help() {
  484.     local dummy;
  485.  
  486.     copyright;
  487.     fprintf(stderr,prt_ln,"Operators Available:");
  488.     fprintf(stderr,prt_ln,"n1 n2 [+ - * /], add subtract multiply divide n1 to n2");
  489.     fprintf(stderr,prt_ln,"n1 n2 %%, n1 remainder of n2");
  490.     fprintf(stderr,prt_ln,"n1 n2 ^, n1 to n2 power");
  491.     fprintf(stderr,prt_ln,"n1 n2 [& | @], n2 bit-wise [ and or xor ] n2");
  492.     fprintf(stderr,prt_ln,"n1 n2 [<< >>], n1 shifted [ left right ] n2 bits");
  493.     fprintf(stderr,prt_ln,"n1 n2 swap, swap n1/n2 on stack top");
  494.     fprintf(stderr,prt_ln,"n1 n2 atan2, arc_tan(n1/n2), -π to π");
  495.     fprintf(stderr,prt_ln,"n1 ~, one's complement of n1");
  496.     fprintf(stderr,prt_ln,"n1 var=, set variable 'var' to n1");
  497.     fprintf(stderr,prt_ln,"n1 var-, delete variable 'var'");
  498.     fprintf(stderr,prt_ln,"var, display value of variable var");
  499.     fprintf(stderr,prt_ln,"deg/rad, assume degrees/radians for trig. functions (rad default)");
  500.     fprintf(stderr,prt_ln,"built-in single argument functions:");
  501.     fprintf(stderr,prt_ln,"sin asin cos acos sinh cosh log log10 int exp sqrt fract push pop");
  502.     fprintf(stderr,prt_ln,"+/-, -/+, +-, -+  change sign of top of stack");
  503.     fprintf(stderr,prt_ln,"= display value on top of stack");
  504.     fprintf(stderr,prt_ln,"=s display values for entire stack");
  505.     fprintf(stderr,prt_ln,"[Qq](uit)? to quit, [Ss](tat)? to display calculator status");
  506.     fprintf(stderr,prt_ln,"[Cc](ls)? to clear screen, [Hh](elp)? to display this help");
  507.     fprintf(stderr,prt_ln,"\nPress <Enter> to Continue. [Qq](uit)?<Enter> to Return to Calculations.");
  508.     getline(dummy);
  509.     if ( dummy ~~ Quit ) return;
  510.     copyright;
  511.     fprintf(stderr,prt_ln,"rtd   - top of stack converted from radians to degrees");
  512.     fprintf(stderr,prt_ln,"dtr   - top of stack converted from degrees to radians");
  513.     fprintf(stderr,prt_ln,"cti   - top of stack converted from cm to inches");
  514.     fprintf(stderr,prt_ln,"itc   - top of stack converted from inches to cm");
  515.     fprintf(stderr,prt_ln,"ktm   - top of stack converted from kilometers to miles");
  516.     fprintf(stderr,prt_ln,"mtk   - top of stack converted from miles to kilometers");
  517.     fprintf(stderr,prt_ln,"ltg   - top of stack converted from Liters to gallons");
  518.     fprintf(stderr,prt_ln,"gtl   - top of stack converted from gallons to Liters");
  519.     fprintf(stderr,prt_ln,"jdn   - compute julian day number from date (yr mo day jdn)");
  520.     fprintf(stderr,prt_ln,"cal   - compute date from julian day number");
  521.     fprintf(stderr,prt_ln,"calm  - display calender 3 month calender centered on month (year month)");
  522.     fprintf(stderr,prt_ln,"calmh - display highlighted 3 month calender centered on month (year month day)");
  523.     fprintf(stderr,prt_ln,"pmonth - display highlighted 3 month calender centered on current month");
  524.     fprintf(stderr,prt_ln,"dow   - compute day of week, Sunday == 0 (yr mo day dow)");
  525.     fprintf(stderr,prt_ln,"now   - sets top of stack to current time");
  526.     fprintf(stderr,prt_ln,"greg  - toggle between Gregorian (default) and Julian calenders");
  527.     fprintf(stderr,prt_ln,"hrs   - compute hours from hour, minute, second (hr min sec hrs)");
  528.     fprintf(stderr,prt_ln,"hms   - compute hour, minute, second from hours");
  529.     fprintf(stderr,prt_ln,"fdate - compute date days in future (past)");
  530.     fprintf(stderr,prt_ln,"For cal/hms/fdate/ functions, append 's' to leave result on stack");
  531. }
  532.  
  533. # function to display calculator status
  534. function stat() {
  535.     local j;
  536.  
  537.     copyright;
  538.     fprintf(stderr,"Calculator Status:\n");
  539.     fprintf(stderr,"Calender Set: %s.\n",greg_jul ? "Julian" : "Gregorian");
  540.     fprintf(stderr,"Assume %s for Trig. Functions\n",DEGREES ? "Degrees" : "Radians");
  541.     fprintf(stderr,"Defined variables:\n");
  542.     for ( j in vars ) {
  543.     ostr = addcomma(vars[j]);
  544.     fprintf(stderr,"%s == %s\n",j,ostr);
  545.     }
  546. }
  547.  
  548. # function to add commas to numbers
  549. function addcomma(x) {
  550.     local num;
  551.     local spat;
  552.     local bnum = /{_d}{3,3}([,.]|$)/;
  553.  
  554.     if ( x < 0 ) return "-" addcomma(-x);
  555.     num = sprintf("%.14g",x);        # num is dddddd.dd
  556.     spat = num ~~ /\./ ? /{_d}{4,4}[.,]/ : /{_d}{4,4}(,|$)/;
  557.     while ( num ~~ spat ) sub(bnum,",&",num);
  558.     return num;
  559. }
  560.  
  561. function prompt() {
  562.     printf("<>");
  563. }
  564.  
  565. # function to clear screen and home cursor
  566. function cls() {
  567.       # clear screen and home cursor string
  568.     local num_lines = 25;
  569.  
  570.     while ( num_lines-- ) print "";
  571. }
  572.  
  573. # function to compute day of week 0 == Sunday, 6 == Saturday
  574. function day_of_week(yr,month,day) {
  575.     return (jdn(yr,month,day) + 1) % 7;
  576. }
  577.  
  578. # function to display monthly calender for year/month passed
  579. function month_cal(yr,month,day) {
  580.     local t1i = jdn(yr,month,1);
  581.     local t2i, i, j;
  582.     local nmnth = month + 1, nyr = yr;
  583.  
  584.     if ( nmnth == 13 ) { nmnth = 1; nyr++; }
  585.     t2i = jdn(nyr,nmnth,1) - t1i;
  586.     t1i = (t1i + 1) % 7;
  587.     print month_array[month],yr;
  588.     print hdr_line;
  589.     for ( i = 1 , j = 7 ; i <= t2i ; ) {
  590.     if ( t1i ) {
  591.         t1i--;
  592.         printf("   ");
  593.       } else {
  594.         if ( i == day ) printf("\x01b[1;32;40m");
  595.         printf("%3u",i);
  596.         if ( i == day ) printf("\x01b[0;37;44m");
  597.         i++;
  598.     }
  599.     if ( i <= t2i && !--j ) {
  600.         print "";
  601.         j = 7;
  602.     }
  603.     }
  604.     print "";
  605. }
  606.  
  607. # function to display 3 month calender
  608. function three_month(yr,mn,dy) {
  609.     local lyr = yr, lmn = mn, nyr = yr, nmn = mn;
  610.  
  611.     if ( --lmn < 1 ) { lmn = 12; lyr--;}
  612.     if ( ++nmn > 12 ) { nmn = 1; nyr++;}
  613.     month_cal(lyr,lmn,0);
  614.     month_cal(yr,mn,dy);
  615.     month_cal(nyr,nmn,0);
  616. }
  617.