/************************************************************************
 *                   lib.c                                              *
 ************************************************************************/
/*  Adds source code for Library Functions from the Library             *
 *  File - LIB.DAT                                                      *
 ************************************************************************
 *   Part of the project : BASCY  Version 1.0                           *
 *   Copyright (C) 2001 - S. Narasimhan, No.11, Sathya Nagar,           *
 *                        MADURAI-625018. INDIA                         *
 *                       email: narasimhan_s_@hotmail.com               *
 ************************************************************************
 * This program is free software; you can redistribute it and/or modify *
 * it under the terms of the GNU General Public License as published by *
 * the Free Software Foundation; either version 2 of the License, or    *
 * (at your option) any later version.                                  *
 *                                                                      *
 * This program is distributed in the hope that it will be useful,      *
 * but WITHOUT ANY WARRANTY; without even the implied warranty of       *
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the        *
 * GNU General Public License for more details.                         *
 *                                                                      *
 * You should have received a copy of the GNU General Public License    *
 * along with this program; if not, write to the Free Software          *
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.            *
 *                                                                      *
 ************************************************************************/
#include "basic.h"
extern unsigned int lincount;
extern unsigned int gosubcount, retcount;
extern int timehcount;
extern int coniocount;
extern int dircount, processcount;
extern FILE *fin, *fout, *ftmp, *ffun;
extern struct symbol symtab[];
extern char indent[];
int libcode(char *fn)
/* Instals/ writes the code for the builtin/library function - fn
 * in the file ffun */
{
        int s, status;
        char header[8];
        char t[2], n[6];
        t[0] = 255;t[1] = '\0';
        s = lookup(fn);
        if(s < 0) {
                error(237) ; /* No such Builtin Function */
                return -1;
        }
        status = symtab[s].u.ival;
        if(status < 0) { /* -ve means Corresponding code is not available
                          * in the translated file*/
            status = -status;
            symtab[s].u.ival = status; /* change status to +ve i.e.available */
          /* From 'status', make the 'header' string to be searched for
           * in the file 'LIB.DAT'. The header string is made as under :
           * 1st char of 'header' is 0xFF.
           * Subsequent to this the index number of the builtin is
           *  appended & the last char is again 0xFF */
            strcpy(header,t);
            num2str(status,n); 
            strcat(header,n);  
            strcat(header,t);
            if(strcmp(fn,"ABS") != 0 && strcmp(fn,"SGN") != 0)
              if(copycode(header) < 0) /* Copy corresponding code for the function */
                 return -1;            /* from LIB.DAT into our translation */
            switch(status) {            
                case  1 : fprintf(fout, "\n#define ABS(x)   (((x) < 0.0) ? -(x) : (x))");
                          fflush(fout);
                          break;
                case  2 : if(libcode("SQR") < 0) return -1;
                          fprintf(fout,"\ndouble %s();",fn);
                          fflush(fout);
                          break;
                case  3 : 
                case  4 :
                case 10 :
                case 11 : fprintf(fout,"\ndouble %s();",fn);
                          fflush(fout);
                          if(libcode("ABS") < 0) return -1;
                          break;
                case  5 :
                case  8 :
                case 12 :
                case 13 :
                case 23 :
                case 26 :
                case 27 :
                case 30 :
                case 43 :
                case 49 : fprintf(fout,"\ndouble %s();",fn);
                          fflush(fout);
                          break;
                case  6 : fprintf(fout,"\ndouble %s();",fn);
                          fprintf(fout,"\n#define LN2       0.693147180559945309417");
                          fflush(fout);
                          break;
                case  7 :
                          fprintf(fout,"\n#define LN10   2.30258509299404568402");
                          fprintf(fout,"\ndouble %s();",fn);
                          fflush(fout);
                          if(libcode("LOG") < 0) return -1;
                          break;
                case  9 : fprintf(fout, "\n#define SGN(x)  (((x) > 0.0) ? 1 : ((x) < 0.0) ? -1 : 0)");
                          fflush(fout);
                          break;
                case 14 : fprintf(fout,"\nchar *CHR_();");
                          fflush(fout);
                          break;
                case 15 : fprintf(fout,"\nchar *LEFT_();");
                          fflush(fout);
                          break;
                case 16 : fprintf(fout,"\nchar *MID_();");
                          fflush(fout);
                          break;
                case 17 : fprintf(fout,"\nchar *RIGHT_();");
                          fflush(fout);
                          break;
                case 18 : fprintf(fout,"\nchar *SPACE_();");
                          fflush(fout);
                          break;
                case 19 :
                          fprintf(fout,"\n#define MAXFLOAT  2.1E+9");
                          fprintf(fout,"\n#define MINFLOAT  2.1E-9");
                          fprintf(fout,"\nchar *STR_();");
                          fflush(fout);
                          break;
                case 21 :
                          fprintf(fout,"\ndouble %s();",fn);
                          fflush(fout);
                          if(libcode("str2num") < 0) return -1;
                          break;
                case 24 : fprintf(fout, "\ndouble %s();",fn);
                          fprintf(fout, "\ndouble mod();");
                          fflush(fout);
                          break;
                case 25 : fprintf(fout,"\ndouble %s();",fn);
                          fflush(fout);
                          if(libcode("EXP") < 0) return -1;
                          if(libcode("LOG") < 0) return -1;
                          break;
                case 28 : fprintf(fout,"\ndouble %s();",fn);
                          fflush(fout);
                          if(libcode("SIN") < 0) return -1;
                          break;
                case 29 :
                          fprintf(fout,"\ndouble %s();",fn);
                          fflush(fout);
                          if(libcode("COS") < 0) return -1;
                          break;
                case 31 : fprintf(fout,"\nchar *LTRIM_();");
                          fflush(fout);
                          break;
                case 32 : fprintf(fout,"\nchar *RTRIM_();");
                          fflush(fout);
                          break;
                case 33 : fprintf(fout,"\nchar *LCASE_();");
                          fflush(fout);
                          break;
                case 34 : fprintf(fout,"\nchar *UCASE_();");
                          fflush(fout);
                          break;
                case 35 : fprintf(fout,"\nchar *TRIM_();");
                          fflush(fout);
                          break;
                case 36 :
                          fprintf(fout,"\ndouble %s();",fn);
                          fflush(fout);
                          if(libcode("TAN") < 0) return -1;
                          break;
                case 38 : fprintf(fout,"\nchar *HEX_();");
                          fflush(fout);
                          break;
                case 39 : fprintf(fout,"\nchar *OCT_();");
                          fflush(fout);
                          break;
                case 40 : fprintf(fout,"\nchar *EnvN_();");
                          fprintf(fout,"\nchar *EnvS_();");
                          fflush(fout);
                          break;
                case 41 : fprintf(fout,"\nchar *STRING_();");
                          fflush(fout);
                          break;
                case 44 : fprintf(fout,"\nchar *DATE_();");
                          fflush(fout);
                          timehcount++;
                          break;
                case 45 : fprintf(fout,"\nchar *TIME_();");
                          fflush(fout);
                          timehcount++;
                          break;
                case 46 : fprintf(fout,"\ndouble TIMER();");
                          fflush(fout);
                          timehcount++;
                          break;
		case 48 : fprintf(fout, "\ndouble LOF();");
                          fflush(fout);
                case 47 : IncludeFilInit();
                          break;
                default : break;
            } /* switch */
        } /* end of if */
        else
                return 0;
} /* End - libcode */
void num2str(int i, char *s)
/* Convert the unsigned integer i (Max. 5 digits) into string s */
{
   int j,k,c;
   char *t;
   t = s;
   do {
      *s++ = i % 10 + '0';
   }while((i /= 10) > 0);
   *s = '\0';
   s = t;
   for(j = 0, k = strlen(s) -1; j < k; j++, k--) {
      c = s[j];
      s[j] = s[k];
      s[k] = c;
   }
} /* End - num2str */
int copycode(char *s)
/* Write the code for the BUILTIN corresponding to the header - 's'
 * from the file LIB.DAT into our .fun file */
{
   FILE *fdat;
   char t[8];
   int c;
   int i ;
   fdat = efopen("LIB.DAT","r");
   do {
     while((c = getc(fdat)) != 255){
       if(c == EOF) {
        fclose(fdat);
        error(24); return -1 ; /*Unexpected end of file LIB.DAT */
       }
     }
     i = 0;
     t[i++] = c;
     while((c = getc(fdat)) != 255) {
        if(c == EOF) {
          fclose(fdat);
          error(24); return -1 ; /*Unexpected end of file LIB.DAT */
        }
        t[i++] = c;
        if(i > 6) {  /* Corrupted file LIB.DAT */
          fclose(fdat);
          error(222);
          return -1;
        } 
     }
     t[i++] = c;
     t[i] = '\0';
     if(strcmp(s,t) == 0) {
        while((c = getc(fdat)) != 255 && c != EOF)
           putc(c,ffun);
        break;
     }
   }while(1 == 1); /* Perpetual loop to be quit by break or error return */
   fclose(fdat);
   return 0;
} /* End - copycode */
int commandprc(void)
{
   fprintf(fout,"\nvoid command();");
   fflush(fout);
   fprintf(ftmp,"\n%scommand(argc, argv);",indent);
   fflush(ftmp);
   fprintf(ffun,"\nvoid command(int argc, char **argv)");
   fprintf(ffun,"\n{");
   fprintf(ffun,"\n  strcpy(COMMAND_,\"\");");
   fprintf(ffun,"\n  while(--argc > 0) {");
   fprintf(ffun,"\n    strcat(COMMAND_,*++argv);");
   fprintf(ffun,"\n    strcat(COMMAND_,\" \");");
   fprintf(ffun,"\n  }");
   fprintf(ffun,"\n}");
   fflush(ffun);
   return 0;
} /* End - commandprc */
void pushprc(void)
{
        fprintf(ffun, "\npushret() /*Increment return stack pointer */");
        fprintf(ffun, "\n{");
        fprintf(ffun, "\n   if(rsptr >= MAXSTACK - 1) {");
        fprintf(ffun, "\n     fprintf(stderr,\"\\nGOSUB nested too deeply\");");
        fprintf(ffun, "\n     exit(1); }");
        fprintf(ffun, "\n   return(rsptr++);");
        fprintf(ffun, "\n}");
        fflush(ffun);
}  /* End - pushprc */
void popprc(void)
{
        fprintf(ffun, "\npopret() /*Decrement return stack pointer */");
        fprintf(ffun, "\n{");
        fprintf(ffun, "\n   if(rsptr == 0) {");
        fprintf(ffun, "\n     fprintf(stderr, \"\\nError: RETURN without GOSUB at line - %d\");",lincount);
	fprintf(ffun, "\n     exit(1); }");
        fprintf(ffun, "\n   return(--rsptr);");
        fprintf(ffun, "\n}");
        fflush(ffun);
} /* End - popprc */
void InitFilePrc(void)
/* Add the requisite data structures and initialization procedures
 * for File Handling */
{
   fprintf(fout, "\n#ifndef MAXFILENUM");
   fprintf(fout, "\n#define MAXFILENUM  %d", (int) MAXFILENUM);
   fprintf(fout, "\n#endif");
   fprintf(fout, "\nFILE *fdList[MAXFILENUM];");
   fprintf(fout, "\nvoid InitFiles();");
   fflush(fout);
   fprintf(ffun, "\nvoid InitFiles(void)");
   fprintf(ffun, "\n{");
   fprintf(ffun, "\n  int i;");
   fprintf(ffun, "\n  for(i = 0; i < %d; i++)", (int) MAXFILENUM);
   fprintf(ffun, "\n     fdList[i] = 0;");
   fprintf(ffun, "\n}");
   fflush(ffun);
} /* End - InitFilePrc() */

void AddHeaders(void)
/* Add the requisite header files */
{
   if(gosubcount > 0 || retcount > 0){

    /* Insert appropriate declarations and code in target file for
     * translation of GOSUB and RETURN statements. */

       fprintf(fout, "\n#include  <setjmp.h>");
       fprintf(fout, "\n#define   MAXSTACK   100");
       fprintf(fout, "\njmp_buf   rtnstack[MAXSTACK];");
       fprintf(fout, "\nint       rsptr = 0;");
       fflush(fout);
       pushprc();  /* Instal the function to push rtn location */
       popprc();   /* Instal the function to pop rtn location */
   }
   fprintf(fout, "\n#include <stdio.h>");
   fprintf(fout, "\n#include <string.h>");
   fprintf(fout, "\n#include <stdlib.h>");
   if(timehcount > 0)
       fprintf(fout,"\n#include <time.h>");
   if(coniocount > 0)
#ifdef  __TURBOC__
       fprintf(fout,"\n#include <conio.h>");
#else
       error(203);
#endif
   if(processcount > 0)
       fprintf(fout, "\n#include <process.h>");
   if(dircount > 0){
#ifdef __TURBOC__ 
       fprintf(fout, "\n#include <dir.h>");
#else
#ifdef  __GNUC__
       fprintf(fout, "\n#include <unistd.h>");
#else
       error(203);
#endif
#endif
   }
   fflush(fout);
} /* End of AddHeaders */

void SetIndent(void)
/* Sets indentation to next level */
{
   int i,j, k;
   i = strlen(indent);
   k = MIN(i+ISIZE, MAXINDENT);
   for(j = i; j < k; j++)
     indent[j] = ' ';
   indent[j] = '\0';
} /* End of setindent */

void DeIndent(void)
/* Folds the indent to the previous level */
{
   int i;
   i = strlen(indent);
   i = MAX(i-ISIZE, 0);
   indent[i] = '\0';
}  /* End of DeIndent */

