#define _USE_MATH_DEFINES
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <stdint.h>

// WGS84 标准椭球参数
#define WGS84_A     6378137.0
#define WGS84_F_INV 298.257223563
#define WGS84_F     (1.0 / WGS84_F_INV)
#define WGS84_E2    (2.0 * WGS84_F - WGS84_F * WGS84_F)

static uint32_t le32_to_cpu(const unsigned char *buf)
{
    return ((uint32_t)buf[3] << 24) | ((uint32_t)buf[2] << 16) |
           ((uint32_t)buf[1] << 8)  | (uint32_t)buf[0];
}

static void print_str_with_hex(const char *str, int len)
{
    int i;
    printf("'");
    for(i = 0; i < len; i++){
        unsigned char c = (unsigned char)str[i];
        if(c >= 32 && c <= 126)
            putchar(c);
        else
            putchar('.');
    }
    printf("' [0x");
    for(i = 0; i < len; i++){
        printf("%02X", (unsigned char)str[i]);
    }
    printf("]");
}

static void print_u8_with_hex(unsigned char val)
{
    printf("%u [0x%02X]", val, val);
}

static void print_u16_with_hex(unsigned short val)
{
    printf("%u [0x%04X]", val, val);
}

static void print_raw4_with_hex(const unsigned char *buf)
{
    printf("[0x%02X%02X%02X%02X]", buf[0], buf[1], buf[2], buf[3]);
}

static void print_double_with_hex(double val)
{
    unsigned char *p = (unsigned char*)&val;
    printf("%.8lf [0x", val);
    printf("%02X%02X%02X%02X%02X%02X%02X%02X",
           p[7], p[6], p[5], p[4], p[3], p[2], p[1], p[0]);
    printf("]");
}

static void print_float_with_hex(float val)
{
    unsigned char *p = (unsigned char*)&val;
    printf("%.4f [0x%02X%02X%02X%02X]", val, p[3], p[2], p[1], p[0]);
}

// LLH(度, m) → XYZ
static void llh2xyz(double lat_deg, double lon_deg, double h,
                    double *x, double *y, double *z)
{
    double B = lat_deg * M_PI / 180.0;
    double L = lon_deg * M_PI / 180.0;

    double sinB = sin(B);
    double cosB = cos(B);
    double sinL = sin(L);
    double cosL = cos(L);

    double N = WGS84_A / sqrt(1.0 - WGS84_E2 * sinB * sinB);
    *x = (N + h) * cosB * cosL;
    *y = (N + h) * cosB * sinL;
    *z = (N * (1.0 - WGS84_E2) + h) * sinB;
}

// XYZ → LLH
static void xyz2llh(double X, double Y, double Z,
                    double *lat_deg, double *lon_deg, double *h)
{
    double L_rad = atan2(Y, X);
    *lon_deg = L_rad * 180.0 / M_PI;

    double r = sqrt(X*X + Y*Y);
    double B_rad = atan2(Z, r);
    double sinB, N, dB;
    int iter = 0;
    const double eps = 1e-12;

    do
    {
        sinB = sin(B_rad);
        N = WGS84_A / sqrt(1.0 - WGS84_E2 * sinB * sinB);
        double tanB_new = (Z + N * WGS84_E2 * sinB) / r;
        double B_new = atan(tanB_new);
        dB = fabs(B_new - B_rad);
        B_rad = B_new;
        iter++;
    } while (dB > eps && iter < 50);

    *lat_deg = B_rad * 180.0 / M_PI;

    sinB = sin(B_rad);
    N = WGS84_A / sqrt(1.0 - WGS84_E2 * sinB * sinB);
    *h = r / cos(B_rad) - N;
}

#pragma pack(1)
typedef struct RawBinHead512
{
    char head_info[53];
    char reserve0[5];

    unsigned char day;
    unsigned char mon;
    unsigned short year;

    char reserve1[18];

    double lat;
    double lon;
    double  alt;

    unsigned char pos_unit;
    unsigned short ant_h_raw;

    char start_end[16];
    unsigned char ant_type_code;
    char reserve2[1];
    char ant_name[20];

    unsigned char ant_meas_mode;
    unsigned char ant_def_en;

    unsigned char edge_R_raw[4];
    unsigned char edge_H_raw[4];
    unsigned char HL1_raw[4];
    unsigned char HL2_raw[4];

    unsigned char freq_mode;
    unsigned char board_type;
    unsigned char rec_mode;

    char soft_ver[15];
    char marker_name[16];
    char marker_no[4];

    unsigned char ant_mask;
    char rec_info[20];
    char ant_sn[20];
    char observer[20];
    char agency[20];
    char marker_type[20];

    short de;
    short dn;
    char reserve_end[206];
} RawBinHead512;
#pragma pack()

typedef char check_size[sizeof(RawBinHead512) == 512 ? 1 : -1];

int ReadBin512(const char *filepath, RawBinHead512 *out)
{
    FILE *fp = fopen(filepath, "rb");
    if (!fp)
    {
        perror("fopen failed");
        return -1;
    }

    memset(out, 0, sizeof(RawBinHead512));
    size_t read_size = fread(out, 1, sizeof(RawBinHead512), fp);
    fclose(fp);

    printf("Struct size: %zu bytes\n", sizeof(RawBinHead512));
    printf("Read bytes: %zu\n\n", read_size);

    if (read_size < 512)
    {
        fprintf(stderr, "WARN: file <512 bytes, incomplete header, all data will be 0!\n");
        return -2;
    }
    return 0;
}

// ===================== RINEX头部结构体 =====================
typedef struct{
    char sys;
    char obs_code[4];
    double shift;
}PhsItem;

typedef struct{
    char sys;
    int obs_cnt;
    char obs_str[130];
}SysObsItem;

typedef struct{
    char sat[4];
    int fn;
}GloFrqItem;

typedef struct{
    char ver[10];
    char prog[22];
    char tool[22];
    char create_time[30];

    char mark_name[32];
    char mark_no[16];
    char mark_type[64];
    char observer[64];
    char agency[64];

    char rcv_sn[22];
    char rcv_mod[22];
    char rcv_ver[22];
    char ant_sn[22];
    char ant_mod[22];

    double XYZ[3];
    double HEN[3];

    SysObsItem obs_list[6];
    char sig_unit[10];

    double interval;
    int t_start_y,t_start_m,t_start_d,t_start_h,t_start_mi;
    double t_start_sec;
    int t_end_y,t_end_m,t_end_d,t_end_h,t_end_mi;
    double t_end_sec;
    char time_sys[5];
    int rcv_clk_app;

    PhsItem phs_arr[30];
    int phs_num;

    int glo_cnt;
    GloFrqItem glo_list[30];
    double glo_bias[3];

    int leap_sec;
    char comm[5][80];
    int comm_cnt;
}RinexHead;

void write_rinex_header(FILE *fp,RinexHead *hd)
{
    int i,j,idx;
    fprintf(fp,"%9sOBSERVATION DATA    M (MIXED)           RINEX VERSION / TYPE\n",hd->ver);
    // 修复：严格20字符分栏，无粘连
    fprintf(fp,"%-20s%-20s%s PGM / RUN BY / DATE \n",hd->prog,hd->tool,hd->create_time);
    fprintf(fp,"       G = GPS       R = GLONASS       C = COMPASS          COMMENT             \n");
    fprintf(fp,"       S = SBAS      J = QZSS          E = GALILEO          COMMENT             \n");
    fprintf(fp,"%-52sMARKER NAME         \n",hd->mark_name);
    fprintf(fp,"%-52sMARKER NUMBER      \n",hd->mark_no);
    fprintf(fp,"%-52sMARKER TYPE       \n",hd->mark_type);
    fprintf(fp,"%-52sOBSERVER / AGENCY \n",hd->observer);
    fprintf(fp,"%-20s%-20s%s     REC # / TYPE / VERS \n",hd->rcv_sn,hd->rcv_mod,hd->rcv_ver);
    fprintf(fp,"%-20s%s                                  ANT # / TYPE        \n",hd->ant_sn,hd->ant_mod);
    fprintf(fp,"%14.4f%16.4f%16.4f                  APPROX POSITION XYZ \n",hd->XYZ[0],hd->XYZ[1],hd->XYZ[2]);
    fprintf(fp,"%12.4f%12.4f%12.4f                  ANTENNA: DELTA H/E/N\n",hd->HEN[0],hd->HEN[1],hd->HEN[2]);
    for(i=0;i<6;i++){
        fprintf(fp,"%c%4d %-60sSYS / # / OBS TYPES \n",
            hd->obs_list[i].sys,hd->obs_list[i].obs_cnt,hd->obs_list[i].obs_str);
    }
    fprintf(fp,"%-52sSIGNAL STRENGTH UNIT\n",hd->sig_unit);
    fprintf(fp,"%10.3f                                                  INTERVAL            \n",hd->interval);
    fprintf(fp,"%6d%5d%5d%5d%5d%11.7f     %s         TIME OF FIRST OBS   \n",
        hd->t_start_y,hd->t_start_m,hd->t_start_d,hd->t_start_h,hd->t_start_mi,hd->t_start_sec,hd->time_sys);
    fprintf(fp,"%6d%5d%5d%5d%5d%11.7f     %s         TIME OF LAST OBS    \n",
        hd->t_end_y,hd->t_end_m,hd->t_end_d,hd->t_end_h,hd->t_end_mi,hd->t_end_sec,hd->time_sys);
    fprintf(fp,"%6d                                                      RCV CLOCK OFFS APPL \n",hd->rcv_clk_app);
    for(i=0;i<hd->phs_num;i++){
        fprintf(fp,"%c %-4s%8.5f                                              SYS / PHASE SHIFT \n",
            hd->phs_arr[i].sys,hd->phs_arr[i].obs_code,hd->phs_arr[i].shift);
    }
    idx=0;
    while(idx < hd->glo_cnt){
        char tmpbuf[128]={0};
        int pos=0;
        for(j=0;j<8 && idx<hd->glo_cnt;j++){
            pos += sprintf(tmpbuf+pos,"%s %d ",hd->glo_list[idx].sat,hd->glo_list[idx].fn);
            idx++;
        }
        fprintf(fp,"%sGLONASS SLOT / FRQ #\n",tmpbuf);
    }
    // 优化：仅打印规范要求的C1C C2P，移除多余C2C
    fprintf(fp,"C1C   %7.3f C2P   %7.3f                     GLONASS COD/PHS/BIS \n",
        hd->glo_bias[0],hd->glo_bias[2]);
    fprintf(fp,"%6d                                                      LEAP SECONDS        \n",hd->leap_sec);
    for(i=0;i<hd->comm_cnt;i++){
        fprintf(fp,"%-52sCOMMENT\n",hd->comm[i]);
    }
    fprintf(fp,"                                                            END OF HEADER\n");
}

static void FillRinexHead(const RawBinHead512 *bin, RinexHead *rh, double X, double Y, double Z, double lat, double lon, double h)
{
    memset(rh, 0, sizeof(RinexHead));
    strcpy(rh->ver, "3.02");
    strcpy(rh->prog, "BinToRinex Converter");
    strcpy(rh->tool, "StaticToRinex");
    strcpy(rh->create_time, "20260620 100000 LCL");

    strncpy(rh->mark_name, bin->marker_name, sizeof(rh->mark_name)-1);
    strncpy(rh->mark_no, bin->marker_no, sizeof(rh->mark_no)-1);
    strncpy(rh->mark_type, bin->marker_type, sizeof(rh->mark_type)-1);
    strncpy(rh->observer, bin->observer, sizeof(rh->observer)-1);
    strncpy(rh->agency, bin->agency, sizeof(rh->agency)-1);

    // 修复1：接收机字段映射修正
    strncpy(rh->rcv_sn, bin->rec_info, sizeof(rh->rcv_sn)-1);
    const char *board_str[] = {"","OEMV","OEM4","DATAGIRD","HEMISPHERE","JAVAD","","UBLOX","CSI","BD970"};
    if(bin->board_type < 10 && board_str[bin->board_type][0] != '\0')
        strcpy(rh->rcv_mod, board_str[bin->board_type]);
    strncpy(rh->rcv_ver, bin->soft_ver, sizeof(rh->rcv_ver)-1);

    // 天线SN空填充0，对齐官方格式
    if(bin->ant_sn[0] == '\0'), len2, "%d-%02d-%02d %02d:%02d:%02d", calendarTime.tm_year + 1900,
                       calendarTime.tm_mon + 1, calendarTime.tm_mday,
                       calendarTime.tm_hour, calendarTime.tm_min, calendarTime.tm_sec);

        printf("end_week:%d end_second:%d  [%s]\n", end_week, end_second, et);

        strcpy(rh->ant_sn, "0");
    else
        strncpy(rh->ant_sn, bin->ant_sn, sizeof(rh->ant_sn)-1);
    strncpy(rh->ant_mod, bin->ant_name, sizeof(rh->ant_mod)-1);

    rh->XYZ[0] = X;
    rh->XYZ[1] = Y;
    rh->XYZ[2] = Z;

    double ant_h_m = (double)bin->ant_h_raw / 1000.0;
    double edge_R = le32_to_cpu(bin->edge_R_raw) / 10000.0;
    double edge_H = le32_to_cpu(bin->edge_H_raw) / 10000.0;
    rh->HEN[0] = ant_h_m + edge_H;
    rh->HEN[1] = edge_R;
    rh->HEN[2] = 0.0;

    // 优化2：观测模板对齐StaticToRinex民用简化标准
    rh->obs_list[0].sys='G';
    rh->obs_list[0].obs_cnt=12;
    strcpy(rh->obs_list[0].obs_str,"C1C L1C D1C S1C C2C L2C D2C S2C C5Q L5Q D5Q S5Q");

    rh->obs_list[1].sys='R';
    rh->obs_list[1].obs_cnt=8;
    strcpy(rh->obs_list[1].obs_str,"C1C L1C D1C S1C C2P L2P D2P S2P");

    rh->obs_list[2].sys='C';
    rh->obs_list[2].obs_cnt=8;
    strcpy(rh->obs_list[2].obs_str,"C1I L1I D1I S1I C7I L7I D7I S7I");

    rh->obs_list[3].sys='S';
    rh->obs_list[3].obs_cnt=4;
    strcpy(rh->obs_list[3].obs_str,"C1C L1C D1C S1C");

    rh->obs_list[4].sys='J';
    rh->obs_list[4].obs_cnt=12;
    strcpy(rh->obs_list[4].obs_str,"C1C L1C D1C S1C C2S L2S D2S S2S C5Q L5Q D5Q S5Q");

    rh->obs_list[5].sys='E';
    rh->obs_list[5].obs_cnt=12;
    strcpy(rh->obs_list[5].obs_str,"C1C L1C D1C S1C C5Q L5Q D5Q S5Q C7Q L7Q D7Q S7Q");

    strcpy(rh->sig_unit,"DBHZ");
    rh->interval = 15.0;

    // 时间：使用bin日期，预留真实观测时间扩展接口
    rh->t_start_y = bin->year;
    rh->t_start_m = bin->mon;
    rh->t_start_d = bin->day;
    rh->t_start_h = 0; rh->t_start_mi = 0; rh->t_start_sec = 0.0;
    rh->t_end_y = bin->year;
    rh->t_end_m = bin->mon;
    rh->t_end_d = bin->day;
    rh->t_end_h = 23; rh->t_end_mi = 59; rh->t_end_sec = 59.9999999;
    strcpy(rh->time_sys,"GPS");
    rh->rcv_clk_app = 0;

    // 优化3：相位偏移对齐官方民用模板
    PhsItem plist[]={
        {'G',"L1C",0.00000},{'G',"L2C",-0.25000},{'G',"L5Q",-0.25000},
        {'R',"L1C",0.00000},{'R',"L2P",0.25000},
        {'C',"L1I",0.00000},{'C',"L7I",0.00000},
        {'S',"L1C",0.00000},
        {'J',"L1C",0.00000},{'J',"L2S",0.00000},{'J',"L5Q",-0.25000},
        {'E',"L1C",0.50000},{'E',"L5Q",-0.25000},{'E',"L7Q",-0.25000},
    };
    rh->phs_num = sizeof(plist)/sizeof(PhsItem);
    memcpy(rh->phs_arr,plist,sizeof(plist));

    rh->glo_cnt=10;
    GloFrqItem gdata[]={
        {"R01",1},{"R02",-4},{"R03",5},{"R09",-2},{"R14",-7},
        {"R15",0},{"R16",-1},{"R17",4},{"R18",-3},{"R19",3}
    };
    memcpy(rh->glo_list,gdata,sizeof(gdata));
    rh->glo_bias[0]=71.950;rh->glo_bias[1]=71.950;rh->glo_bias[2]=71.950;
    rh->leap_sec=18;

    char buf[128];
    snprintf(rh->comm[0], sizeof(rh->comm[0]), "*** Above antenna height is from mark to PHASE CENTER.");
    snprintf(rh->comm[1], sizeof(rh->comm[1]), "    31     4        %.4f        ANT MEASURE TYPE/HEIGT", rh->HEN[0]);
    snprintf(buf, sizeof(buf), "    %.4f    %.4f    %.4f    %.4f    0.0000", edge_R, edge_H, le32_to_cpu(bin->HL1_raw)/10000.0, le32_to_cpu(bin->HL2_raw)/10000.0);
    strcpy(rh->comm[2], buf);
    strcpy(rh->comm[3], "                    BASE STATION");
    rh->comm_cnt = 4;
}

void PrintBinHead(const RawBinHead512 *p)
{
    uint32_t raw_R  = le32_to_cpu(p->edge_R_raw);
    uint32_t raw_H  = le32_to_cpu(p->edge_H_raw);
    uint32_t raw_HL1= le32_to_cpu(p->HL1_raw);
    uint32_t raw_HL2= le32_to_cpu(p->HL2_raw);

    double edge_R_val  = raw_R / 10000.0;
    double edge_H_val  = raw_H / 10000.0;
    double HL1_val     = raw_HL1 / 10000.0;
    double HL2_val     = raw_HL2 / 10000.0;

    double ant_h_mm  = (double)p->ant_h_raw / 1000.0;

    double lat_deg, lon_deg;
    if (p->pos_unit == 0)
    {
        lat_deg = p->lat * 180.0 / M_PI;
        lon_deg = p->lon * 180.0 / M_PI;
    }
    else
    {
        lat_deg = p->lat;
        lon_deg = p->lon;
    }

    double H_ant = (double)p->alt;
    printf("\n------ llh [%.8f][%.8f][%.4f]\n", lat_deg, lon_deg, H_ant);

    double X, Y, Z;
    llh2xyz(lat_deg, lon_deg, H_ant, &X, &Y, &Z);
    double chk_lat, chk_lon, chk_h;
    xyz2llh(X, Y, Z, &chk_lat, &chk_lon, &chk_h);

    printf("==================== 512 BIN HEADER PARSE RESULT ====================\n");
    printf("Head info: "); print_str_with_hex(p->head_info, sizeof(p->head_info)); printf("\n");
    printf("Date: %04u-%02u-%02u [Y:", p->year, p->mon, p->day);
    print_u16_with_hex(p->year); printf(" M:"); print_u8_with_hex(p->mon);
    printf(" D:"); print_u8_with_hex(p->day); printf("]\n\n");

    printf("Coordinate Raw Storage:\n");
    printf("  Lat raw: "); print_double_with_hex(p->lat);
    printf(" (%s)\n", p->pos_unit ? "degree" : "radian");
    printf("  Lon raw: "); print_double_with_hex(p->lon);
    printf(" (%s)\n", p->pos_unit ? "degree" : "radian");
    printf("  Alt raw(float): "); print_float_with_hex(p->alt); printf("\n");
    printf("  Lat convert(deg): %.8f\n", lat_deg);
    printf("  Lon convert(deg): %.8f\n", lon_deg);

    printf("\nElevation Info (No correction macro applied):\n");
    printf("  Antenna phase center WGS84 H: %.3f m\n", H_ant);
    printf("  Antenna height raw: %.3f m (%u mm)\n", ant_h_mm, p->ant_h_raw);

    printf("\nAPPROX POSITION XYZ (Pure llh2xyz, no any ENU offset added):\n");
    printf("  X = %.4f m\n", X);
    printf("  Y = %.4f m\n", Y);
    printf("  Z = %.4f m\n", Z);
    printf("  XYZ: %.4f  %.4f  %.4f\n", X, Y, Z);

    printf("\nXYZ -> LLH Check (for verify):\n");
    printf("  lat=%.8f lon=%.8f h=%.4f\n", chk_lat, chk_lon, chk_h);

    printf("\nAntenna geometry params (stored = float * 10000, little-endian uint32):\n");
    printf("  Edge R: raw=%u  value=%.4f ", raw_R, edge_R_val); print_raw4_with_hex(p->edge_R_raw); printf("\n");
    printf("  Edge H: raw=%u  value=%.4f ", raw_H, edge_H_val); print_raw4_with_hex(p->edge_H_raw); printf("\n");
    printf("  L1 HL1: raw=%u  value=%.4f ", raw_HL1, HL1_val); print_raw4_with_hex(p->HL1_raw); printf("\n");
    printf("  L2 HL2: raw=%u  value=%.4f ", raw_HL2, HL2_val); print_raw4_with_hex(p->HL2_raw); printf("\n");

    printf("Freq mode: %s [", p->freq_mode == 1 ? "Dual" : "Single");
    print_u8_with_hex(p->freq_mode);
    printf("]\n");

    const char *board_str[] = {"Undefined","OEMV","OEM4","DATAGIRD","HEMISPHERE","JAVAD","Empty","UBLOX","CSI","BD970"};
    printf("Board Type: %d (%s) [", p->board_type, p->board_type < 10 ? board_str[p->board_type] : "Reserved");
    print_u8_with_hex(p->board_type);
    printf("]\n");

    printf("Rec Mode: %s [", p->rec_mode == 0 ? "Static/Base" : "Rover");
    print_u8_with_hex(p->rec_mode);
    printf("]\n");

    printf("Software Version: ");
    print_str_with_hex(p->soft_ver, sizeof(p->soft_ver));
    printf("\n");
    printf("Marker Name: "); print_str_with_hex(p->marker_name, sizeof(p->marker_name)); printf("\n");
    printf("Marker No: "); print_str_with_hex(p->marker_no, sizeof(p->marker_no)); printf("\n");
    printf("Antenna Mask: 0x%02X [", p->ant_mask); print_u8_with_hex(p->ant_mask); printf("]\n");
    if (p->ant_mask & 0x01) printf("  - Phase Center Offset\n");
    if (p->ant_mask & 0x02) printf("  - Antenna Measure Mode\n");
    if (p->ant_mask & 0x04) printf("  - Vertical Antenna Height\n");
    if (p->ant_mask & 0x08) printf("  - Measure Point Marker\n");
    if (p->ant_mask & 0x10) printf("  - Height From Antenna Bottom\n");
    printf("Rec Info(SN): "); print_str_with_hex(p->rec_info, sizeof(p->rec_info)); printf("\n");
    printf("Antenna SN: "); print_str_with_hex(p->ant_sn, sizeof(p->ant_sn)); printf("\n");
    printf("Observer: "); print_str_with_hex(p->observer, sizeof(p->observer)); printf("\n");
    printf("Agency: "); print_str_with_hex(p->agency, sizeof(p->agency)); printf("\n");
    printf("Marker Type: "); print_str_with_hex(p->marker_type, sizeof(p->marker_type)); printf("\n");
    printf("Horizontal Eccentricity: E=%d mm, N=%d mm (Not used for XYZ)\n", p->de, p->dn);
    printf("====================================================================\n");
}

int main(int argc, char *argv[])
{
    if (argc != 2)
    {
        printf("Usage: %s bin_static_file.dat\n", argv[0]);
        return 1;
    }
    RawBinHead512 hdr;
    int ret = ReadBin512(argv[1], &hdr);
    if (ret != 0)
        return ret;

    PrintBinHead(&hdr);

    double lat_deg, lon_deg;
    if (hdr.pos_unit == 0)
    {
        lat_deg = hdr.lat * 180.0 / M_PI;
        lon_deg = hdr.lon * 180.0 / M_PI;
    }
    else
    {
        lat_deg = hdr.lat;
        lon_deg = hdr.lon;
    }
    double h_geo = (double)hdr.alt;
    double X, Y, Z;
    llh2xyz(lat_deg, lon_deg, h_geo, &X, &Y, &Z);

    RinexHead rh;
    FillRinexHead(&hdr, &rh, X, Y, Z, lat_deg, lon_deg, h_geo);

    char outname[256];
    snprintf(outname, sizeof(outname), "%s_rinex302_head.txt", argv[1]);
    FILE *fp = fopen(outname, "w");
    if (!fp)
    {
        perror("Failed to create rinex header output file");
        return -1;
    }
    write_rinex_header(fp, &rh);
    fclose(fp);
    printf("\n[OK] Generated RINEX3.02 header file: %s\n", outname);
    return 0;
}