/************************************************
 *                                              *
 *       ***************************            *
 *       *  HAPPy Pascal Compiler  *            *
 *       ***************************            *
 * ( HAPPy = H.Asano Pascal Processing system ) *
 *                                              *
 *     Original program                         *
 *             ---  Pascal P4 ---               *
 *                                              *
 *     Pascal-P4は、public domainらしい｡        *
 *     このHAPPyの著作権は浅野比富美にある｡     *
 *     HAPPyは、Pascal-p4のソースをもとに、     *
 *     アルゴリズムにたちかえって解析し、       *
 *     PascalからC言語に書換え､ISO7185規格に    *
 *     準拠させるため、独自の創作を加えたもの   *
 *     である｡ とはいっても、やっぱり物真似で　 *
 *     あることは充分承知しています。           *
 *                                              *
 *        Copyright(c) H.Asano. 1992-1994.      *
 *           All rights resereved.              *
 *                                              *
 ************************************************/

#define EXTERN                          /* pascomp.hで使用            */

#define abnormal  1                     /* usage関数への引数          */
#define normal    0                     /* usage関数への引数          */

#define NormalEnd     0                 /* 正常終了の終了コード       */
#define CompileError  1                 /* コンパイルエラーの終了コード*/
#define EtcError      2                 /* その他のエラーの終了コード */

#include <stdio.h>
#include <string.h>
#include <process.h>
#include <stdlib.h>
#include <jctype.h>
#include "version.h"
#include "pascomp.h"

extern void init(void) ;                /* 初期設定処理               */
extern void programme(void);            /* promgramのコンパイル処理   */

FILE *passource ;                       /* pascalソースファイルポインタ */
FILE *pcdfile   ;                       /* P-codeソースファイルポインタ */

const  char *asm = "PA.OVL"  ;          /* アセンブラのファイル名     */
const  char *sext = ".pas"   ;          /* Pascalソースファイル拡張子 */
const  char *oext = ".pco"   ;          /* P-codeｵﾌﾞｼﾞｪｸﾄﾌｧｲﾙ拡張子　 */
const  char *PcodeSourceName = "pcode.pcs" ; /* P-codeソースファイル名*/
static char *TempPath        ;          /* 環境変数 TMP の 設定内容   */
static char PcodeSname[50]   ;          /* P-codeソースファイルフルパス*/
static char PcodeOname[50]   ;          /* P-codeオブジェクトファイル名*/
static char path[50]         ;          /* コンパイラコマンドのパス名 */

static boolean asmlst = false  ;

/**************************************/
/*    usage() : 使用方法出力処理      */
/**************************************/
static void usage(int type)
{
if(type == abnormal)
 fputs("\nC001: 起動パラメータが誤っている\n",stderr);
else {
 fputs("\n  HAPPy is the H.Asano Pascal Processing system. (^_^)\n",
             stderr);
 fputs(
  "\n  HAPPyはISO7185規格水準0にほぼ準拠したMS-DOS汎用Pascal処理系です。\n",
           stderr) ;
 fputs("  HAPPyの複写・再配付は自由です。\n", stderr) ;
}

 fputs("\n  pcｺﾏﾝﾄﾞはPascalｿｰｽからｶﾚﾝﾄﾃﾞｨﾚｸﾄﾘにP-codeｵﾌﾞｼﾞｪｸﾄ(ｿｰｽ名.pco)を\n",
         stderr);
 fputs("  作ります。できたｵﾌﾞｼﾞｪｸﾄはpiｺﾏﾝﾄﾞで実行させます。\n\n",stderr);

 fputs("  使い方:  pc [ ｵﾌﾟｼｮﾝ... ] Pascalｿｰｽﾌｧｲﾙ名[.pas] [ ｵﾌﾟｼｮﾝ... ]\n",
       stderr) ;
 fputs("  ｵﾌﾟｼｮﾝ:\n",stderr);
 fputs("     -c ･･･ 構文チェックのみ行う\n",stderr);
 fputs("     -a ･･･ アセンブルリストを標準出力に出力する\n",stderr);
 fputs("     -d ･･･ 範囲チェック等を行うコードを生成する\n",stderr);

     exit(EtcError);                    /* その他のエラーで終了       */
}

/**********************************************/
/* getobjname() : オブジェクトファイル名取得  */
/**********************************************/
static void getobjname(void)
{
  int i = 0 ;
  int j = 0 ;

/*  ドライブ ':' \ディレクトリ\ディレクトリ\ ... \ファイル名 '.' 拡張子
    という構成のソースファイルフルパスより 最後のファイル名を取り出し
    拡張子 "pco" を付与する (漢字対応) */

     if(passname[1] == ':') i=j=2         ;
     do {
      if     (iskanji(passname[i])) i++   ;
      else if(passname[i] == '\\')  j=i+1 ;
     } while(passname[i++] != '.')        ; /* ｼﾌﾄJIS2ﾊﾞｲﾄ目と'.'は重ならない*/
     strncpy(PcodeOname,passname+j,i-j-1) ;
     strcpy(PcodeOname+i-j-1,oext)        ;
}

/**************************************/
/* argment() : 起動アーギュメント処理 */
/**************************************/
static void argment(int argc,char *argv[])
{
  int  i,j  ;
  boolean getfileflag = false ;

    if(argc < 2)  usage(normal);        /* アーギュメントなしはusage  */

    for(i=strlen(*argv)-1;*(*argv+i)!='\\';i--) ; /* パスを取得       */
    strncpy(path,*argv,i+1) ;
    path[i+2] = '\0' ;
    TempPath = getenv("TMP") ;          /* 環境変数 TMP を取得        */
    pcode = true  ;                     /* Pコード出力要(ﾃﾞﾌｫﾙﾄ)      */
    pcdinf= false ;                     /* Pコード情報出力不要(ﾃﾞﾌｫﾙﾄ)*/
    debug = false ;                     /* 範囲チェック不要(ﾃﾞﾌｫﾙﾄ)   */
    while(--argc) {
     if(**++argv == '-') {
      for(i=1;*(*argv+i)!='\0';i++)
       switch(*(*argv+i)) {
        case 'C' :
        case 'c' : pcode  = false ;
                   break          ;
        case 'A' :
        case 'a' : pcode  = true  ;
                   pcdinf = true  ;
                   asmlst = true  ;
                   break          ;
        case 'D' :
        case 'd' : debug  = true  ;
                   break          ;
        default  : usage(abnormal);
       }
      if(i==1)  usage(abnormal);        /* - だけの時はusage          */
     }
     else {
      if(getfileflag) {                 /* すでにソースファイル名を   */
        usage(abnormal);                /* 取得している時は 誤り      */
        break ;                         /* whileループ脱出            */
      }
      getfileflag = true      ;
      *passname   = '\0'      ;
      strcpy(passname, *argv) ;
      j=0 ;                             /* 拡張子が省略されているか   */
      while((*(passname+j)!='\0') && (*(passname+j)!='.')) j++ ;
      if(*(passname+j)=='\0') strcat(passname,sext) ; /* 拡張子を付与 */
     }
    }

    if(getfileflag) {                   /* ファイル名が指定された時   */
     passource = fopen(passname,"r");
     if(passource == NULL) {
      fprintf(stderr,"C002: Pascalソースファイル(%s)がない\n", passname);
      exit(EtcError);
     }
     getobjname() ;                     /* オブジェクトファイル名取得 */
    }
    else usage(abnormal) ;              /* ファイル名の指定がない時   */

    if(pcode) {
     strcpy(PcodeSname,TempPath) ;
     if(iskanji(*(PcodeSname+strlen(PcodeSname)-2)) ||  /* 最後が漢字 */
       (*(PcodeSname+strlen(PcodeSname)-1) != '\\'))    /* or \でない */
      strcat(PcodeSname,"\\") ;                         /* \ を追加   */
     strcat(PcodeSname,PcodeSourceName) ;
     pcdfile = fopen(PcodeSname,"w");
     if(pcdfile == NULL) {
      fprintf(stderr,"C003: P-codeソースファイル(%s)が作れない\n",PcodeSname) ;
      exit(EtcError);
     }
    }
}

/***************************************/
/*         term() : 終了処理           */
/***************************************/
void term(void)
{
  int resultcode ;
  char instsize[7]  ;
  char assembler[50] ;

    if(pcode && (errorcount == 0)) {
     fputs(" *** Compile  completed. ***\n",stderr) ;
     fclose(pcdfile) ;
     strcpy(assembler, strcat(path,asm)) ;
     sprintf(instsize,"%d",ic) ;
     if(asmlst)
      resultcode=execl(assembler,"",    /* アセンブルリスト出力指定   */
                       instsize,PcodeSname,PcodeOname,version,"l",NULL);
     else
      resultcode=execl(assembler,"",    /* 通常のアセンブル           */
                       instsize,PcodeSname,PcodeOname,version,NULL) ;

     if(resultcode == -1) {             /* アセンブラが起動できない   */
      fprintf(stderr,"C004: アセンブラ(%s)が起動できない\n",assembler) ;
      exit(EtcError) ;
     }
    }
    else if(errorcount != 0) {
     fprintf(stderr," *** %d errors detected. Fail in compile ***\n",
                      errorcount);
    exit(CompileError) ;
    }
    else {                              /* pcode = false              */
     fputs(" *** No Error ***\n",stderr);
     exit(NormalEnd) ;
    }
}

/**************************************/
/*       main() : メイン処理          */
/**************************************/
void main(int argc,char *argv[])
{

     fprintf(stderr,
 "HAPPy Pascal Compiler Version %s  Copyright (c) H.Asano 1992-1994.\n",
                                version) ;

     argment(argc,argv) ;               /* 起動アーギュメント処理     */

     init() ;                           /* compiler 初期設定処理      */

     programme();                       /* programのコンパイル        */

     term() ;                           /* 終了処理                   */
}
