home *** CD-ROM | disk | FTP | other *** search
/ Graphics Plus / Graphics Plus.iso / libs / gle / util / letz / cmd.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-11-29  |  25.9 KB  |  1,166 lines

  1. /*    number    - put it in current cell and move in current dir
  2.     'string   - put string in cell and move in current direction
  3.     range = expression  - evaluate exp for each cell in range
  4.     cell(exp,exp) = expression  - evaluate exp and put in cell
  5.     cmd    - exectue command, if then else next for save load generate
  6.                    print, input
  7.     & = continued on next line.
  8.  
  9.     load b.dat  range c3r3   width 10.3  between ", "
  10.     save b.c  c3c4
  11.     set outwidth 0
  12.     set outwidth 10.3
  13.     set between ", "
  14.     copy c1 c2
  15. */
  16.  
  17. #include "all.h"
  18. #include <math.h>
  19. #include <time.h>
  20. #include "edt.h"
  21. #include "keyword.h"
  22. range_next(RANGE *r);
  23. range_def(char *s, RANGE *r);
  24. sort_shuffle(int i, int r1, int *pnt);
  25. passcmd(char *source,char *tk[],int *ntok);
  26. do_assign(char *t1, char *t2);
  27. extern int in_recover;
  28. extern int curx;
  29. extern int cury;
  30. extern int max_x,max_y;
  31. #define tok(j) (tk[j])
  32. #define dbg if (gle_debug>0)
  33. extern char file_name[];
  34. extern int iserr;
  35. extern int gle_debug,changed;
  36. extern int trace_on;
  37. extern int exit_manip;
  38. int isating;
  39. int islogging;
  40. int load_list;
  41. int dpoints;
  42. int outwidth1=8,outwidth2=8;
  43. char *between=" ";
  44. char strmiss[40];
  45. /*---------------------------------------------------------------------------*/
  46. do_command(char *cmd)
  47. {
  48.     static char inbuff[200];
  49.     static char *tk[500];
  50.     static char tkbuff[500];
  51.     int i,al,ntok,f;
  52.     char space_str[] = " ";
  53.  
  54.     if (islogging) log_write(cmd);
  55.     
  56.     token_space();
  57.     strcat(inbuff,cmd);
  58.     al = strlen(inbuff);
  59.     if (inbuff[al-1]=='&') {
  60.         inbuff[al-1] = 0;
  61.         return;
  62.     }
  63.     token(&inbuff,tk,&ntok,tkbuff);
  64.     for (i=ntok+1;i< ntok+5;i++) tk[i] = &space_str;
  65.     dbg for (i=1;i<=ntok;i++) printf("token{%s} ",tk[i]);
  66.     dbg printf("\n");
  67.     passcmd(inbuff,tk,&ntok);
  68.     inbuff[0] = 0;
  69.  
  70. }
  71.  
  72. extern int moving_x, moving_y;
  73.  
  74.  
  75. passcmd(char *source,char *tk[],int *ntok)
  76. {
  77.     int etype,sub_start,sub_end,i,f,np,ix,vidx,vtype=1;
  78.     double v;
  79.     char *sp;
  80.     etype = 1;
  81.     find_mkey(tok(1),&ix);
  82.     if (strcmp(tok(2),"=")==0)  {
  83.         do_assign(tok(1),tok(3));
  84.         return;
  85.     }
  86.     sp = strchr(tok(1),'=');
  87.     if (sp!=NULL) {
  88.         *sp = 0;
  89.         do_assign(tok(1),sp+1);
  90.         return;
  91.     }
  92.     if (isnumber(tok(1))) {
  93.         set_cell(curx,cury,atof(tok(1)));
  94.         set_newxy(curx+moving_x,cury+moving_y);
  95.         return;
  96.         }
  97.     if ((*tok(1))=='"') {
  98.         *(tok(1)+strlen(tok(1))-1) = 0;
  99.         set_scell(curx,cury,tok(1)+1);
  100.         set_newxy(curx+moving_x,cury+moving_y);
  101.         return;
  102.         }
  103.     if ((*tok(1))=='@') {
  104.         at_open(tok(1)+1);
  105.         return;
  106.     }
  107.     switch (ix) {
  108.       case k_data: /* data <range> */
  109.         cmd_data(tok(2));
  110.         break;
  111.       case k_help:/* help load */
  112.         if (*ntok==1) do_help("MANIP","");
  113.         else do_help(tok(2),tok(3));
  114.         refresh();
  115.         break;
  116.       case k_list: /* list a.a [range] , reads a list of numbers */
  117.         load_list = true;
  118.         cmd_load(tok(2),tok(3),*ntok);
  119.         load_list = false;
  120.         break;
  121.       case k_load: /* LOAD  A.A  [range] -LIST */
  122.         if (*ntok>3) if (strcmp(tok(4),"-LIST")==0) load_list = true;
  123.         cmd_load(tok(2),tok(3),*ntok);
  124.         load_list = false;
  125.         break;
  126.       case k_save: /* SAVE [a.a] [range] [format-string] */
  127.         changed = false;
  128.         cmd_save(tok(2),tok(3),tok(4),*ntok);
  129.         break;
  130.       case k_set: /* set outwidth, set width, set between, */
  131.         if (strcmp(tok(2),"OUTWIDTH")==0) set_outwidth(tok(3));
  132.         else if (strcmp(tok(2),"WIDTH")==0) set_outwidth(tok(3));
  133.         else if (strcmp(tok(2),"BETWEEN")==0) between = unquote(tok(3));
  134.         else if (strcmp(tok(2),"MISSING")==0) strcpy(strmiss,unquote(tok(3)));
  135.         else if (strcmp(tok(2),"DIGITS")==0) outwidth2 = atoi(tok(3));
  136.         else if (strcmp(tok(2),"DPOINTS")==0) dpoints = atoi(tok(3));
  137.         else if (strcmp(tok(2),"COLUMNS")==0) set_ncol(atoi(tok(3)));
  138.         else if (strcmp(tok(2),"NCOL")==0) set_ncol(atoi(tok(3)));
  139.         else if (strcmp(tok(2),"COLWIDTH")==0) set_colwidth(atoi(tok(3)));
  140.         else if (strcmp(tok(2),"PRECISION")==0) outwidth2 = atoi(tok(3));
  141.         else if (strcmp(tok(2),"SIZE")==0) {
  142.             set_size(atoi(tok(3)),atoi(tok(4)));
  143.         }
  144.         else fner("Invalid SET command, Use (width,between,digits,dpoints,ncol,colwidth)\n");
  145.         break;
  146.       case k_new: /* clears the spreadsheet and free's memory */
  147.         clear_data();
  148.         break;
  149.       case k_clear: /* clear part of the spread sheet */
  150.         cmd_clear(tok(2));
  151.         break;
  152.       case k_delete: /* delete <range> [if <exp>] */
  153.         cmd_delete(tok(2),tok(4),*ntok);
  154.         break;
  155.       case k_insert: /* insert <range> */
  156.         cmd_insert(tok(2));
  157.         break;
  158.       case k_exit:
  159.         cmd_save(tok(2),tok(3),tok(4),*ntok);
  160.         changed = false;
  161.         exit_manip = true;
  162.         break;
  163.       case k_quit:
  164.         exit_manip = true;
  165.         break;
  166.       case k_logging: /* log filename */
  167.         if (islogging) log_close();
  168.         log_open(tk[2]);
  169.         break;
  170.       case k_close:
  171.         log_close();
  172.         break;
  173.       case k_at: /* execute file of manip commands */
  174.         at_open(tk[2]);
  175.         break;
  176.       case k_call:
  177.         refresh();
  178.         break;
  179.       case k_sort: /* sort <range> on <exp> */
  180.         cmd_sort(tk[2],tk[4],*ntok);
  181.         break;
  182.       case k_swap: /* swap CaCb  || swap RaRb */
  183.         cmd_swap(tk[2]);
  184.         break;
  185.       case k_shell:
  186.         window(1,1,80,25); scr_norm(); clrscr();
  187.         printf("Type in EXIT to return to MANIP\n\n");
  188.         system("");
  189.         refresh();
  190.         break;
  191.       case k_sum:
  192.         cmd_sum(tk[2]);
  193.         break;
  194.       case k_fit:
  195.         cmd_fit(tk[2]);
  196.         break;
  197.       case k_parsum:
  198.         cmd_parsum(tk[2],tk[3]);
  199.         break;
  200.       case k_if:
  201.       case k_else:
  202.       case k_end:
  203.       case k_for:
  204.       case k_next:
  205.       case k_print:
  206.       case k_input: /* input "prompt" variable */
  207.       case k_copy: /* copy range1  range2  [if exp] (doesn't) */
  208.         cmd_copy(tk[2],tk[3],tk[5],*ntok,true);
  209.         break;
  210.       case k_move: /* move range1  range2  [if exp] (leaves gaps) */
  211.         cmd_copy(tk[2],tk[3],tk[5],*ntok,false);
  212.         break;
  213.       case k_prop: /* prop range1  range2  (cycle thru range1)  */
  214.         cmd_copy(tk[2],tk[3],tk[5],*ntok,2);
  215.         break;
  216.       case k_generate: /* gen 2(1,2:4)3  c1  (1 1 2 2 3 3 4 4) 3 times*/
  217.         cmd_generate(tk[2],tk[3],*ntok);
  218.         break;
  219.       case k_let:
  220.         /* let variable = expression */
  221.         var_findadd(tk[2],&vidx,&vtype);
  222.         evaluate(tk[4],&v);
  223.         var_set(vidx,v);
  224.         break;
  225.       case k_goto: /* should really use eval, not atoi so var's work */
  226.         set_newxy(atoi(tk[2]),atoi(tk[3]));
  227.         break;
  228.       default:
  229.         fner("No such command {%s} {%s}\n",tk[1],tk[2]);
  230.     }
  231. }
  232. struct op_key { char *name; int typ; int pos; long idx; } ;
  233. typedef struct op_key (*OPKEY)[100];
  234.  
  235.  
  236. do_assign(char *t1, char *t2)
  237. {
  238.     RANGE rr;
  239.     int cp,vtype,vidx;
  240.     double v;
  241.     long pcode[200];
  242.     char outstr[80];
  243.     int plen;
  244.     vtype = 1;
  245.  
  246.         /* ------------------         */
  247.         /* variable = expression     */
  248.         /* cell(exp,exp) = exp         */
  249.         /* range = exp             */
  250.         /* ------------------         */
  251.  
  252.     if (strncmp(t1,"CELL(",5)==0) {        /* cell(exp,exp) = exp */
  253.       {     char s1[80],s2[80],*s;
  254.         int x,y;
  255.         s = strchr(t1,',');
  256.         if (s==NULL) {
  257.             fner("Expecting CELL(EXP,EXP) = EXP \n");
  258.             return;
  259.         }
  260.         strcpy(s1,t1+5); strcpy(s2,s+1);
  261.         *strchr(s1,',') = 0;
  262.         if (strchr(s2,')')!=NULL) *strchr(s2,')') = 0;
  263.         evaluate(s1,&v); x = v;
  264.         evaluate(s2,&v); y = v;
  265.         evaluate(t2,&v);
  266.         set_cell(x,y,v);
  267.         show_ifcell(x,y);
  268.       }
  269.       return;
  270.     }
  271.     if (range_def(t1,&rr)) {                   /* range = exp */
  272.      {
  273.        int c_idx[20], c_val[20], nc, j;
  274.        int r_idx[20], r_val[20], nr;
  275.  
  276.         polish(t2,pcode,&plen,&vtype);
  277.         var_find_rc(c_idx,c_val,&nc,'C');
  278.         var_find_rc(r_idx,r_val,&nr,'R');
  279.         for (;range_next(&rr);) {
  280.             cp = 0;
  281.             eval_setxy(rr.col,rr.row);
  282.             for (j=0;j<nc;j++) {
  283.                 var_set(c_idx[j],vcell(c_val[j],rr.row));
  284.             }
  285.             for (j=0;j<nr;j++) {
  286.                 var_set(r_idx[j],vcell(rr.col,r_val[j]));
  287.             }
  288.             eval(pcode,&cp,&v,outstr,&vtype);
  289.             set_cell(rr.col,rr.row,v);
  290.             show_ifcell(rr.col,rr.row);
  291.         }
  292.         return;
  293.      }
  294.     }
  295.     fner("error, expecting cell(exp,exp) = exp, or range = exp \n");
  296. }
  297. evaluate(char *exp, double *v)
  298. {
  299.     long pcode[200];
  300.     int plen,vtype,cp;
  301.     char outstr[100];
  302.  
  303.     vtype = 1;
  304.     polish(exp,pcode,&plen,&vtype);
  305.     if (plen>150) fner("pcode too long, report bug to Chris\n");
  306.     cp = 0;
  307.     eval(pcode,&cp,v,outstr,&vtype);
  308. }
  309. int new_line;
  310. range_next(RANGE *r)
  311. {
  312.     new_line = false;
  313.     if (r->row==0) {
  314.         r->row = r->r1; r->col = r->c1;
  315.         return true;
  316.     }
  317.     if (r->colfirst) {
  318.         r->col++;
  319.         if (r->col > r->c2) {
  320.             new_line = true;
  321.             r->col = r->c1;
  322.             r->row++;
  323.             if (r->row > r->r2) return false;
  324.         }
  325.     } else {
  326.         r->row++;
  327.         if (r->row > r->r2) {
  328.             new_line = true;
  329.             r->row = r->r1;
  330.             r->col++;
  331.             if (r->col > r->c2) return false;
  332.         }
  333.     }
  334.     return true;
  335. }
  336. range_def(char *s, RANGE *r)
  337. {
  338.     char *s1;
  339.     char rr,cc;
  340.  
  341.     strip_colon(s);
  342.     r->c1 = r->c2 = r->r1 = r->r2 = r->row = r->col = 0;
  343.  
  344.     if (*s=='C') {cc='C'; rr='R'; r->colfirst = true;}
  345.     else if (*s=='R') {cc='R'; rr='C'; r->colfirst = false;}
  346.     else return false;
  347. /*    c1   c1r1r10   c3c4r7 c3r7  c3c4r1r2 |   r1r2c1c3   c3r7  r2*/
  348.  
  349.     s1 = range_int(s,&(r->c1));
  350.     if (*s1==cc) {
  351.         s1 = range_int(s1,&r->c2);
  352.     }
  353.     if (*s1==rr) {
  354.         s1 = range_int(s1,&r->r1);
  355.         if (*s1==cc) {
  356.             s1 = range_int(s1,&r->c2);
  357.         }
  358.         if (*s1==rr) {
  359.             s1 = range_int(s1,&r->r2);
  360.         }
  361.         if (*s1==cc) {
  362.             s1 = range_int(s1,&r->c2);
  363.         }
  364.     }
  365.     if (!r->colfirst) {
  366.         swapint(&r->c1,&r->r1);
  367.         swapint(&r->c2,&r->r2);
  368.     }
  369.     if (r->c1 == 0) r->c1 = 1;
  370.     if (r->c2 == 0) {
  371.       if (!r->colfirst) {
  372.         if (r->c1 > max_x) r->c2 = r->c1; else r->c2 = max_x;
  373.       } else {
  374.         r->c2 = r->c1;
  375.       }
  376.     }
  377.     if (r->r1 == 0) r->r1 = 1;
  378.     if (r->r2 == 0) {if (r->colfirst)
  379.         { if (r->r1>max_y) r->r2 = r->r1; else r->r2 = max_y;}
  380.       else r->r2 = r->r1;}
  381.  
  382. /*       printf("range def %d %d   %d %d  | \n",r->c1,r->r1,r->c2,r->r2); getch();*/
  383.     data_setsize(r->c2,r->r2);
  384.     if (*s1!=0) return false;
  385.     return true;
  386. }
  387. char *range_int(char *s, int *v)
  388. {
  389.     static char buff[40],*b;
  390.     b = buff;
  391.     for (s++;*s!=NULL && isdigit(*s);)
  392.         *b++ = *s++;
  393.     *b++ = 0;
  394.     *v = atoi(buff);
  395.     return s;
  396. }
  397. swapint(int *a, int *b)
  398. {
  399.     int c;
  400.     c = *a;
  401.     *a = *b;
  402.     *b = c;
  403. }
  404. char *sep_chars=", \t\n";
  405. cmd_load(char *fname, char *range, int ntok)
  406. {
  407.     RANGE rr;
  408.     char inbuff[2001];
  409.     FILE *fptr;
  410.     int i;
  411.  
  412.     if (ntok<2) fname = file_name;
  413.     strcpy(file_name,fname);
  414.  
  415.     if (ntok>2) {
  416.      if (range_def(range,&rr)) range_next(&rr);
  417.      else  {                   /* range = exp */
  418.          fner("Invalid load range given (%s) \n",range);
  419.          return;
  420.      }
  421.     } else {
  422.      rr.col = 1;  rr.row = 1;
  423.     }
  424.     fptr = fopen(fname,"r");
  425.     if (fptr==NULL) {
  426.         fner("Could not open (%s) \n",fname);
  427.         return;
  428.     }
  429.     for (;!feof(fptr);) {
  430.         if (fgets(inbuff,2000,fptr)!=NULL) {
  431.             if (load_list) cmd_load_list(&rr,inbuff);
  432.             else cmd_load_line(rr.col,rr.row++,inbuff);
  433.         }
  434.     }
  435.     fclose(fptr);
  436. }
  437. cmd_load_list(RANGE *r, char *inbuff)
  438. {
  439.     char *s;
  440.     s = strtok(inbuff,sep_chars);
  441.     for (;s!=NULL;) {
  442.         load_str(r->col,r->row,s);
  443.         s = strtok(NULL,sep_chars);
  444.         range_next(r);
  445.     }
  446.  
  447. }
  448. cmd_load_line(int x, int y, char *inbuff)
  449. {
  450.     char *s;
  451.     s = strtok(inbuff,sep_chars);
  452.     for (;s!=NULL;) {
  453.         load_str(x,y,s);
  454.         s = strtok(NULL,sep_chars);
  455.         x++;
  456.     }
  457.  
  458. }
  459. load_str(int x, int y, char *s)
  460. {
  461.     if (strcmp(s,".")==0 || strcmp(s,"-")==0 || strcmp(s,"*")==0) clear_cell(x,y);
  462.     else if (isdigit(*s) || *s=='-' || *s=='+') set_cell(x,y,atof(s));
  463.     else set_scell(x,y,s);
  464.     show_ifcell(x,y);
  465. }
  466. cmd_save(char *fname, char *range, char *format, int ntok)
  467. {
  468.     RANGE rr;
  469.     char inbuff[2001];
  470.     char fmtg[80],buff1[80];
  471.     FILE *fptr;
  472.     int lcount=0;
  473.     int i,inlen=0,thelot;
  474.     double v;
  475.     char *s;
  476.  
  477.     thelot = false;
  478.     if (*range=='-') {s = range; range = format; format = s;}
  479.     if (strcmp(format,"-COMMA")==0) {
  480.         set_outwidth(0);
  481.         between = strdup(", ");
  482.     }
  483.     if (strcmp(format,"-TAB")==0) {
  484.         set_outwidth(0);
  485.         between = strdup("\t");
  486.     }
  487.     if (strcmp(format,"-SPACE")==0) {
  488.         set_outwidth(0);
  489.         between = strdup(" ");
  490.     }
  491.  
  492.     sprintf(fmtg,"%%.%dg",outwidth2);
  493.     if (outwidth1==0 && outwidth2==0) strcpy(fmtg,"%g");
  494.  
  495.     if (ntok<2) fname = file_name;
  496.     if (strcmp(fname,"*")==0) fname = file_name;
  497.     strcpy(file_name,fname);
  498.  
  499.     /* format strings   "%2.3f, " */
  500.     if (ntok<4) format = "%g ";
  501.     if (ntok<3 || strcmp(range," ")==0) thelot = true;
  502.     if (thelot) range = "C1R1";
  503.     if (range_def(range,&rr)) ;
  504.     else  {                   /* range = exp */
  505.         fner("Invalid range given (%s)%d \n",range,strlen(range));
  506.         return;
  507.     }
  508.     if (thelot) rr.c2 = max_x;
  509.     unlink("manip_.bak");
  510.     unlink("manip_.tmp");
  511.     fptr = fopen("manip_.tmp","w");
  512.     if (fptr==NULL) {
  513.         fner("Could not open (%s) \n",fname);
  514.         return;
  515.     }
  516.     for (;range_next(&rr);) {
  517.         if (new_line==true) {
  518.             fprintf(fptr,"%s\n",inbuff);
  519.             inbuff[50] = 0;
  520.             if (++lcount==1) fner("{%s} W=%d D=%d {%s}",fname,outwidth1,outwidth2,inbuff);
  521.             inlen = 0;
  522.         }
  523.         if (inlen>0) { strcpy(inbuff+inlen,between); inlen +=strlen(between);}
  524.         get_cellboth(rr.col,rr.row,&v,&s);
  525.         if (s==NULL) {
  526.             i = sprintf(buff1,fmtg,vcell(rr.col,rr.row));
  527.             if (dpoints>0) i = strcpydecimal(inbuff+inlen,buff1,outwidth1,dpoints);
  528.             else i = strcpywidth(inbuff+inlen,buff1,outwidth1);
  529.         } else {
  530.             i = strcpywidth(inbuff+inlen,s,outwidth1);
  531.         }
  532.         inlen += i;
  533.     }
  534.     if (new_line==true) {
  535.         fprintf(fptr,"%s\n",inbuff);
  536.             inbuff[50] = 0;
  537.             if (++lcount==1) fner("Width=%d Precision=%d {%s}",outwidth1,outwidth2,inbuff);
  538.         inlen = 0;
  539.     }
  540.     fclose(fptr);
  541.     if (rename(fname,"manip_.bak")!=0);
  542.     if (rename("manip_.tmp",fname)!=0) fner("Unable to rename manip_.tmp");
  543. }
  544. strcpydecimal(char *dest, char *src, int wid, int dpoints)
  545. {
  546.     /* 123 ,  12.031,  0.0003321 */
  547.     /* dpoints 2 goes too   */
  548.     /* 123.00  12.03  0.00  */
  549.     static char buff[80];
  550.     int i;
  551.  
  552.     strcpy(buff,src);
  553.     if (strchr(buff,'.')==NULL) strcat(buff,".");
  554.     strcat(buff,"0000000000000000000000000000000000");
  555.     *(strchr(buff,'.')+dpoints+1) = 0;
  556.     strcpywidth(dest,buff,wid);
  557.     return strlen(dest);
  558. }
  559. strcpywidth(char *dest, char *src, int wid)
  560. {
  561.     static char buff[80];
  562.     int i;
  563.     i = wid-strlen(src);
  564.     if (i<0) i = 0;
  565.     memset(buff,' ',i);
  566.     buff[i] = 0;
  567.     strcpy(dest,buff);
  568.     strcat(dest,src);
  569.     return strlen(dest);
  570. }
  571. set_outwidth(char *s)
  572. {
  573.     char *ss;
  574.     ss = strchr(s,'.');
  575.     if (ss==NULL) {
  576.         outwidth1 = atoi(s);
  577.         outwidth2 = 8;
  578.     } else {
  579.         *ss++ = 0;
  580.         outwidth1 = atoi(s);
  581.         outwidth2 = atoi(ss);
  582.     }
  583. }
  584. char *unquote(char *s)
  585. {
  586.     char ss[80];
  587.     strcpy(ss,s);
  588.     if (*s=='"') {
  589.     ss[strlen(ss)-1] = 0;
  590.     return strdup(ss+1);
  591.     } else return strdup(ss);
  592. }
  593. cmd_copy(char *src, char *dest, char *ifexp, int ntok, int always)
  594. {
  595.     RANGE ss,dd,savess;
  596.     int c_idx[20], c_val[20], nc, j, isif=false;
  597.     int r_idx[20], r_val[20], nr;
  598.     int cp,vtype,vidx,ddok,ssok;
  599.     double v;
  600.     char outstr[30];
  601.     long pcode[200];
  602.     int plen;
  603.     vtype = 1;
  604.  
  605.     if (ntok>4) isif = true;
  606.     if (!range_def(src,&ss)) { fner("Error in source range {%s} \n",src); return;}
  607.     if (!range_def(dest,&dd)) { fner("Error in destination range {%s} \n",dest); return;}
  608.  
  609.     if (isif) {
  610.         polish(ifexp,pcode,&plen,&vtype);
  611.         var_find_rc(c_idx,c_val,&nc,'C');
  612.         var_find_rc(r_idx,r_val,&nr,'R');
  613.     }
  614.     ddok = range_next(&dd);
  615.     ssok = range_next(&ss);
  616.     savess = ss;
  617.     for (;ssok && ddok;) {
  618.         if (isif) {
  619.             cp = 0;
  620.             eval_setxy(ss.col,ss.row);
  621.             eval_setxyd(dd.col,dd.row);
  622.             for (j=0;j<nc;j++) {
  623.                 var_set(c_idx[j],vcell(c_val[j],ss.row));
  624.             }
  625.             for (j=0;j<nr;j++) {
  626.                 var_set(r_idx[j],vcell(ss.col,r_val[j]));
  627.             }
  628.             eval(pcode,&cp,&v,outstr,&vtype);
  629.         }
  630.         if (v==true || !isif) {
  631.             copy_cell(ss.col,ss.row,dd.col,dd.row);
  632.             show_ifcell(dd.col,dd.row);
  633.             ddok = range_next(&dd);
  634.         } else if (always) ddok = range_next(&dd);
  635.         if (always!=2) ddok = true;
  636.         ssok = range_next(&ss);
  637.         if (!ssok && always==2) {
  638.             ss = savess;    ssok = true;
  639.         }
  640.     }
  641. }
  642. gen_next(char *pat, double *v);
  643. cmd_generate(char *patx, char *dest, int ntok)
  644. {
  645.     int left,right;
  646.     RANGE rr;
  647.     char pat[188];
  648.     char middle[80];
  649.     double v;
  650.     int i,j;
  651.  
  652.     strcpy(pat,patx);
  653.     if (strchr(pat,'(')==NULL) {fner("Expecting left bracket"); return;}
  654.     if (strchr(pat,')')==NULL) {fner("Expecting left bracket"); return;}
  655.     if (ntok!=3) {fner("Expecting (GEN pattern range)"); return;}
  656.  
  657.     if (pat[0]=='(') {strcpy(pat,"1"); strcat(pat,patx);}
  658.     if (pat[strlen(pat)-1] == ')') strcat(pat,"1");
  659.     left = atoi(strtok(pat,"()"));
  660.     strcpy(middle,strtok(NULL,"()"));
  661.     right = atoi(strtok(NULL,"()"));
  662.     if (left==0) left = 1;
  663.     if (right==0) right = 1;
  664.     if (!range_def(dest,&rr))  {fner("Invalid range given (%s) \n",dest); return;}
  665.     for (i=0;i<right;i++) {
  666.       gen_next(middle,&v);
  667.       for (;gen_next(NULL,&v);) {
  668.         for (j=0;j<left;j++) {
  669.         range_next(&rr);
  670.         set_cell(rr.col,rr.row,v);
  671.         show_ifcell(rr.col,rr.row);
  672.         }
  673.       }
  674.     }
  675. }
  676. gen_next(char *pat, double *v)
  677. {
  678.     static char *s,p[200];
  679.     static double v1,v2,v3;
  680.     static int instep;
  681.     char *c1,*c2;
  682.     if (pat!=NULL) {
  683.         strcpy(p,pat);
  684.         s = strtok(p,",");
  685.         return true;
  686.     }
  687.     if (instep) {
  688.            v1 += v3;
  689.            *v = v1;
  690.            if (v1<=v2) return true;
  691.            else instep = false;
  692.     }
  693.     if (s==NULL) return false;
  694.     c2 = c1 = strchr(s,':');
  695.     if (c1!=NULL) c2 = strchr(c1+1,':');
  696.  
  697.     if (c1==NULL) {
  698.         *v = atof(s);
  699.         s = strtok(NULL,",");
  700.         return true;
  701.     }
  702.     v1 = atof(s);
  703.     v2 = atof(c1+1);
  704.     if (c2==NULL) v3 = 1; else v3 = atof(c2+1);
  705.     *v = v1;
  706.     instep = true;
  707.     s = strtok(NULL,",");
  708.     if (v1>v2) return false;
  709.     return true;
  710. }
  711. int c_idx[20], c_val[20], ncc;
  712. int r_idx[20], r_val[20], nrr;
  713. long cpcode[200];
  714. cmd_polish(char *exp)
  715. {
  716.     int cp,vtype,vidx,ddok,ssok;
  717.     int plen;
  718.     vtype = 1;
  719.  
  720.     polish(exp,cpcode,&plen,&vtype);
  721.     var_find_rc(c_idx,c_val,&ncc,'C');
  722.     var_find_rc(r_idx,r_val,&nrr,'R');
  723. }
  724. cmd_eval(int x1, int y1, double *v)
  725. {
  726.     int cp,vtype,vidx,ddok,ssok,j;
  727.     char outstr[30];
  728.     vtype = 1;
  729.  
  730.     cp = 0;
  731.     eval_setxy(x1,y1);
  732.     eval_setxyd(x1,y1);
  733.     for (j=0;j<ncc;j++) {
  734.         var_set(c_idx[j],vcell(c_val[j],y1));
  735.     }
  736.     for (j=0;j<nrr;j++) {
  737.         var_set(r_idx[j],vcell(x1,r_val[j]));
  738.     }
  739.     eval(cpcode,&cp,v,outstr,&vtype);
  740. }
  741. cmd_delete(char *range, char *ifexp, int ntok)
  742. {
  743.     RANGE rr;
  744.     double v;
  745.     int isif,i,j,wid,w;
  746.     if (ntok>2) isif = true; else isif = false;
  747.     if (!range_def(range,&rr)) { fner("Error in range {%s} \n",range); return;}
  748.  
  749.     if (isif) cmd_polish(ifexp);
  750.     range_next(&rr);
  751.     if (rr.colfirst) {
  752.         w = rr.c2-rr.c1+1;
  753.         wid = max_x-rr.c1;
  754.     } else {
  755.         w = rr.r2-rr.r1+1;
  756.         wid = max_y-rr.r1;
  757.     }
  758.     for (;;) {
  759.         if (rr.colfirst) {
  760.           if (isif) cmd_eval(rr.col,rr.row,&v);
  761.           if (v==true || !isif) {
  762.             for (j=0;j<wid; j++) {
  763.               copy_cell(rr.col+j+w,rr.row,rr.col+j,rr.row);
  764.               show_ifcell(rr.col+j,rr.row);
  765.             }
  766.             for (j=0;j<w;j++) {
  767.               clear_cell(rr.c2+wid-j,rr.row);
  768.               show_ifcell(rr.c2+wid-j,rr.row);
  769.             }
  770.           }
  771.           rr.row++;
  772.           if (rr.row>rr.r2) break;
  773.         } else {
  774.           if (isif) cmd_eval(rr.col,rr.row,&v);
  775.           if (v==true || !isif) {
  776.             for (j=0;j<wid; j++) {
  777.               copy_cell(rr.col,rr.row+j+w,rr.col,rr.row+j);
  778.               show_ifcell(rr.col,rr.row+j);
  779.             }
  780.             for (j=0;j<w;j++) {
  781.               clear_cell(rr.col,rr.r2+wid-j);
  782.               show_ifcell(rr.col,rr.r2+wid-j);
  783.             }
  784.           }
  785.           rr.col++;
  786.           if (rr.col>rr.c2) break;
  787.         }
  788.     }
  789. }
  790. int oncol;
  791. cmd_sort(char *range, char *ifexp, int ntok)
  792. {
  793.     RANGE rr;
  794.     double v;
  795.     int *pnt;
  796.     int isif,i,j,wid,w,c,savemax;
  797.     if (ntok<3) {fner("Expecting   SORT  c1c2  ON <exp> "); return; }
  798.     if (!range_def(range,&rr)) { fner("Error in range {%s} \n",range); return;}
  799.  
  800.     savemax = max_x;
  801.     oncol = max_x + 1;
  802.     cmd_polish(ifexp);
  803.     range_next(&rr);
  804.     if (ntok==5) {
  805.       for (i=rr.r1;i<=rr.r2;i++) {
  806.         copy_cell(rr.c1,i,oncol,i);
  807.       }
  808.     } else {
  809.       for (i=rr.r1;i<=rr.r2;i++) {
  810.         cmd_eval(rr.c1,i,&v);
  811.         set_cell(oncol,i,v);
  812.       }
  813.     }
  814.     pnt = calloc(max_y+2,sizeof(int));
  815.     if (pnt==NULL) {fner("Not enough memory to sort"); return;}
  816.     for (i=0;i<=max_y+1;i++) pnt[i] = i;
  817.     for (i=rr.r1+1;i<=rr.r2;i++) {
  818.         if (cell_greater(oncol,pnt[i-1],oncol,pnt[i])) {
  819.             sort_shuffle(i,rr.r1,pnt);
  820.         }
  821.     }
  822.     for (c=rr.c1; c<=rr.c2; c++) {
  823.         for (j=rr.r1;j<=rr.r2;j++) {
  824.             copy_cell(c,pnt[j],oncol,j);
  825.         }
  826.         for (j=rr.r1;j<=rr.r2;j++) {
  827.             copy_cell(oncol,j,c,j);
  828.             show_ifcell(c,j);
  829.         }
  830.     }
  831.     for (j=1;j<=max_y;j++) clear_cell(oncol,j);
  832.     max_x = savemax;
  833. }
  834. sort_shuffle(int i, int r1, int *pnt)
  835. {
  836.     int ins,j,x;
  837.     ins = r1;
  838.     for (j=i-1;j>=r1;j--) {
  839.         if (cell_greater(oncol,pnt[i],oncol,pnt[j])) {
  840.             ins = j + 1;
  841.             break;
  842.         }
  843.     }
  844.     x = pnt[i];
  845.     for (j=i;j>=ins;j--) pnt[j] = pnt[j-1];
  846.     pnt[ins] = x;
  847. }
  848. cmd_insert(char *range)
  849. {
  850.     RANGE rr;
  851.     double v;
  852.     int isif,i,j,wid,w,cwid,cw,rwid,rw;
  853.     if (!range_def(range,&rr)) { fner("Error in range {%s} \n",range); return;}
  854.  
  855.     range_next(&rr);
  856.     cw = rr.c2-rr.c1+1;
  857.     cwid = max_x-rr.c1+1;
  858.     rw = rr.r2-rr.r1+1;
  859.     rwid = max_y-rr.r1+1;
  860.     for (;;) {
  861.         if (rr.colfirst) {
  862.             for (j=cwid-1;j>=0; j--) {
  863.               copy_cell(rr.col+j,rr.row,rr.col+j+cw,rr.row);
  864.               show_ifcell(rr.col+j+cw,rr.row);
  865.             }
  866.             for (j=0;j<cw;j++) {
  867.               clear_cell(rr.c1+j,rr.row);
  868.               show_ifcell(rr.c1+j,rr.row);
  869.             }
  870.             rr.row++;
  871.             if (rr.row>rr.r2) break;
  872.         } else {
  873.             for (j=rwid-1;j>=0; j--) {
  874.               copy_cell(rr.col,rr.row+j,rr.col,rr.row+j+rw);
  875.               show_ifcell(rr.col,rr.row+j+rw);
  876.             }
  877.             for (j=0;j<rw;j++) {
  878.               clear_cell(rr.col,rr.r1+j);
  879.               show_ifcell(rr.col,rr.r1+j);
  880.             }
  881.             rr.col++;
  882.             if (rr.col>rr.c2) break;
  883.         }
  884.     }
  885. }
  886. cmd_data(char *range)
  887. {
  888.     RANGE rr;
  889.     char ans[155];
  890.     int cmd;
  891.     if (!range_def(range,&rr)) {
  892.         fner("Invalid range given (%s)%d \n",range,strlen(range));
  893.         return;
  894.     }
  895.     for (;;) {
  896.         range_next(&rr);
  897.         mjl_flush();
  898. xxx:        set_newxy(rr.col,rr.row);
  899.         if (!iserr) fner("Press ^Z or ESC when data entry finished\n");
  900.         read_command(&cmd,ans,"DATA% ");
  901.         if (cmd==eescape || cmd==equit) break;
  902.         if (cmd!=0) {
  903.             do_arrow(cmd);
  904.             rr.col = curx; rr.row = cury;
  905.             goto xxx;
  906.         } else {
  907.           if (isnumber(ans)) {
  908.             set_cell(curx,cury,atof(ans));
  909.           } else {
  910.             set_scell(curx,cury,ans);
  911.           }
  912.           show_cellwide(curx,cury);
  913.         }
  914.     }
  915. }
  916. swap_def(char *s, RANGE *r)
  917. {
  918.     char *s1;
  919.     char rr,cc;
  920.  
  921.     strip_colon(s);
  922.  
  923.     r->c1 = r->c2 = r->r1 = r->r2 = r->row = r->col = 0;
  924.  
  925.     if (*s=='C') {cc='C'; rr='R'; r->colfirst = true;}
  926.     else if (*s=='R') {cc='R'; rr='C'; r->colfirst = false;}
  927.     else return false;
  928. /*    c1   c1r1r10   c3c4r7 c3r7  c3c4r1r2 |   r1r2c1c3   c3r7  r2*/
  929.  
  930.     s1 = range_int(s,&(r->c1));
  931.     if (*s1==cc) {
  932.         s1 = range_int(s1,&r->c2);
  933.     }
  934.     if (*s1==rr) {
  935.         s1 = range_int(s1,&r->r1);
  936.         if (*s1==cc) {
  937.             s1 = range_int(s1,&r->c2);
  938.         }
  939.         if (*s1==rr) {
  940.             s1 = range_int(s1,&r->r2);
  941.         }
  942.         if (*s1==cc) {
  943.             s1 = range_int(s1,&r->c2);
  944.         }
  945.     }
  946.     if (!r->colfirst) {
  947.         swapint(&r->c1,&r->r1);
  948.         swapint(&r->c2,&r->r2);
  949.     }
  950.     if (*s1!=0) return false;
  951.     return true;
  952. }
  953. cmd_swap(char *range)
  954. {
  955.     RANGE rr;
  956.     int i,j;
  957.     if (!swap_def(range,&rr)) {
  958.         fner("Invalid range given (%s) expecting c1c2 or r1r2 \n",range);
  959.         return;
  960.     }
  961.     if (rr.colfirst) {
  962.       j = max_y;
  963.       if (rr.r2!=0) j = rr.r2;
  964.       if (rr.c1==0 || rr.c2==0) {fner("Invalid range, expected c1c2\n"); return;}
  965.       for (i=1;i<=max_y;i++) {
  966.         swap_cell(rr.c1,i,rr.c2,i);
  967.         show_ifcell(rr.c1,i); show_ifcell(rr.c2,i);
  968.       }
  969.     } else {
  970.       j = max_x;
  971.       if (rr.c2!=0) j = rr.c2;
  972.       if (rr.r1==0 || rr.r2==0) {fner("Invalid range, expected r1r2\n"); return;}
  973.       for (i=1;i<=max_x;i++) {
  974.         swap_cell(i,rr.r1,i,rr.r2);
  975.         show_ifcell(i,rr.r1); show_ifcell(i,rr.r2);
  976.       }
  977.     }
  978. }
  979. add_dotman(char *s);
  980. FILE *logfile;
  981. log_open(char *fname)
  982. {
  983.     add_dotman(fname);
  984.     logfile = fopen(fname,"w");
  985.     if (logfile==NULL) {
  986.         fner("Could not open (%s) \n",fname);
  987.         return;
  988.     }
  989.     islogging = true;
  990. }
  991. log_write(char *s)
  992. {
  993.     fprintf(logfile,"%s\n",s);
  994. }
  995. log_close()
  996. {
  997.     if (islogging) fclose(logfile);
  998.     islogging = false;
  999. }
  1000. add_dotman(char *s)
  1001. {
  1002.     if (strstr(s,".")==0) strcat(s,".man");
  1003. }
  1004. FILE *atfile;
  1005. at_open(char *fname)
  1006. {
  1007.     add_dotman(fname);
  1008.     atfile = fopen(fname,"r");
  1009.     if (atfile==NULL) {
  1010.         fner("Could not open (%s) \n",fname);
  1011.         return;
  1012.     }
  1013.     isating = true;
  1014. }
  1015. at_read(char *s)
  1016. {
  1017.     s[0] = 0;
  1018.     if (feof(atfile)) {
  1019.         fclose(atfile); atfile = NULL; isating = false; return false;
  1020.     }
  1021.     s[0] = 0;
  1022.     if (fgets(s,200,atfile)==NULL) return false;
  1023.     return true;
  1024. }
  1025. strip_colon(char *s)
  1026. {
  1027.     char *ss;
  1028.     ss = s;
  1029.     for (;*s!=0;s++) {
  1030.         if (*s!=':') *ss++ = *s;
  1031.     }
  1032.     *ss++ = 0;
  1033. }
  1034. cmd_parsum(char *range, char *dest)
  1035. {
  1036.     RANGE rr,dd;
  1037.     double total=0;
  1038.     if (!range_def(range,&rr)) { fner("Invalid range given (%s) \n",range); return;}
  1039.     if (!range_def(dest,&dd)) { fner("Invalid destination given (%s) \n",range); return;}
  1040.     for (;range_next(&rr);) {
  1041.         range_next(&dd);
  1042.         total = total + vcell(rr.col,rr.row);
  1043.         set_cell(dd.col,dd.row,total);
  1044.         show_ifcell(dd.col,dd.row);
  1045.     }
  1046. }
  1047. rangestd(RANGE *rr, double mean, long numrow, double *variance,
  1048.     double *stddev);
  1049.  
  1050. cmd_sum(char *range)
  1051. {
  1052.     RANGE rr,rrsave;
  1053.     double v,var,stddev;
  1054.     char *s;
  1055.     double total=0;
  1056.     long ntot=0;
  1057.     if (!range_def(range,&rr)) { fner("Invalid range given (%s) \n",range); return;}
  1058.     rrsave = rr;
  1059.     for (;range_next(&rr);) {
  1060.         get_cellboth(rr.col,rr.row,&v,&s);
  1061.         if (s==NULL) {
  1062.             total = total + v;
  1063.             ntot++;
  1064.         }
  1065.     }
  1066.     if (ntot>0) {
  1067.         rangestd(&rrsave,total/ntot,ntot,&var,&stddev);
  1068.         printmess("Total %g, Avg %g, sd %g, var %g, Cells %ld \n",total,total/ntot,stddev,var,ntot);
  1069.     } else fner("No values in range\n");
  1070. }
  1071. rangestd(RANGE *rr, double mean, long numrow, double *variance,
  1072.     double *stddev)
  1073. {
  1074.    int i;
  1075.    char *s;
  1076.    double xsqr,v;
  1077.  
  1078.    xsqr = 0.0;
  1079.    if (numrow<2) return;
  1080.    for (;range_next(rr);) {
  1081.       get_cellboth(rr->col,rr->row,&v,&s);
  1082.       if (s==NULL) {
  1083.     xsqr = xsqr + v*v;
  1084.       }
  1085.    }
  1086.    (*variance) = (xsqr - numrow * mean*mean) / (numrow - 1);
  1087.    (*stddev) = sqrt(fabs((*variance)));
  1088. }
  1089.  
  1090. cmd_clear(char *range)
  1091. {
  1092.     RANGE rr;
  1093.     if (!range_def(range,&rr)) { fner("Invalid range given (%s) \n",range); return;}
  1094.     for (;range_next(&rr);) {
  1095.         clear_cell(rr.col,rr.row);
  1096.         show_ifcell(rr.col,rr.row);
  1097.     }
  1098. }
  1099. fitlsq(RANGE *rrr,int ndata, double *a, double *b, double *siga, double *sigb, double *chi2, double *q);
  1100. cmd_fit(char *range)
  1101. {
  1102.     RANGE rr,rrsave;
  1103.     char *s;
  1104.     double v,a,b,siga,sigb,chi2,q;
  1105.     double total=0;
  1106.     int ntot=0;
  1107.     if (!range_def(range,&rr)) { fner("Invalid range given (%s) \n",range); return;}
  1108.     rr.c2 = rr.c1;
  1109.     rrsave = rr;
  1110.     for (;range_next(&rr);) {
  1111.         get_cellboth(rr.col,rr.row,&v,&s);
  1112.         if (s==NULL) {
  1113.             ntot++;
  1114.         }
  1115.     }
  1116.     if (ntot>0) {
  1117.       fitlsq(&rrsave,ntot,&a,&b,&siga,&sigb,&chi2,&q);
  1118.       printmess("y = %g + b*%g    siga=%g sigb=%g  chi2=%g\n"
  1119.         ,a,b,siga,sigb,chi2);
  1120.     } else fner("No values in range\n");
  1121. }
  1122. static double sqrarg;
  1123. #define SQR(a) (sqrarg=(a),sqrarg*sqrarg)
  1124. fitlsq(RANGE *rrr,int ndata, double *a, double *b, double *siga, double *sigb, double *chi2, double *q)
  1125. {
  1126.     RANGE  rr;
  1127.     double v,x,y,sx=0,sy=0,st2=0,wt,t,ss,sigdat,sxoss;
  1128.     char *s;
  1129.     *b = 0.0;
  1130.     for (rr = *rrr;range_next(&rr);) {
  1131.         get_cellboth(rr.col,rr.row,&x,&s);
  1132.         get_cellboth(rr.col+1,rr.row,&y,&s);
  1133.         if (s==NULL) {
  1134.             sx += x;
  1135.             sy += y;
  1136.         }
  1137.     }
  1138.     ss = ndata;
  1139.     sxoss = sx/ss;
  1140.     for (rr = *rrr;range_next(&rr);) {
  1141.         get_cellboth(rr.col,rr.row,&x,&s);
  1142.         get_cellboth(rr.col+1,rr.row,&y,&s);
  1143.         if (s==NULL) {
  1144.             t=x-sxoss;
  1145.             st2 += t*t;
  1146.             *b += t*y;
  1147.         }
  1148.     }
  1149.     *b /= st2;
  1150.     *a = (sy-sx*(*b))/ss;
  1151.     *siga = sqrt((1.0+sx*sx/(ss*st2))/ss);
  1152.     *sigb = sqrt(1.0/st2);
  1153.     *chi2=0.0;
  1154.     for (rr = *rrr;range_next(&rr);) {
  1155.         get_cellboth(rr.col,rr.row,&x,&s);
  1156.         get_cellboth(rr.col+1,rr.row,&y,&s);
  1157.         if (s==NULL) {
  1158.             *chi2 += SQR(y-(*a)-(*b)*x);
  1159.         }
  1160.     }
  1161.     *q = 1.0;
  1162.     sigdat = sqrt((*chi2)/(ndata-2));
  1163.     *siga *= sigdat;
  1164.     *sigb *= sigdat;
  1165. }
  1166.