/*
 * startrek.c
 *
 * Super Star Trek Classic (v1.1)
 * Retro Star Trek Game 
 * C Port Copyright (C) 1996  <Chris Nystrom>
 * 
 * This program is free software; you can redistribute it and/or modify
 * in any way that you wish. _Star Trek_ is a trademark of Paramount
 * I think.
 * 
 * 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.
 *
 * This is a C port of an old BASIC program: the classic Super Star Trek
 * game. It comes from the book _BASIC Computer Games_ edited by David Ahl
 * of Creative Computing fame. It was published in 1978 by Workman Publishing,
 * 1 West 39 Street, New York, New York, and the ISBN is: 0-89489-052-3.
 * 
 * See http://www.cactus.org/~nystrom/startrek.html for more info.
 *
 * Contact Author of C port at:
 *
 * Chris Nystrom
 * 1013 Prairie Dove Circle
 * Austin, Texas  78758
 *
 * E-Mail: cnystrom@gmail.com, nystrom@cactus.org
 *
 * BASIC -> Conversion Issues
 *
 *     - String Names changed from A$ to sA
 *     - Arrays changed from G(8,8) to g[9][9] so indexes can
 *       stay the same.
 *
 * Here is the original BASIC header:
 *
 * SUPER STARTREK - MAY 16, 1978 - REQUIRES 24K MEMORY
 *
 ***        **** STAR TREK ****        ****
 *** SIMULATION OF A MISSION OF THE STARSHIP ENTERPRISE,
 *** AS SEEN ON THE STAR TREK TV SHOW.
 *** ORIGINAL PROGRAM BY MIKE MAYFIELD, MODIFIED VERSION
 *** PUBLISHED IN DEC'S "101 BASIC GAMES", BY DAVE AHL.
 *** MODIFICATIONS TO THE LATTER (PLUS DEBUGGING) BY BOB
 *** LEEDOM - APRIL & DECEMBER 1974,
 *** WITH A LITTLE HELP FROM HIS FRIENDS . . .
 *** COMMENTS, EPITHETS, AND SUGGESTIONS SOLICITED --
 *** SEND TO:  R. C. LEEDOM
 ***           WESTINGHOUSE DEFENSE & ELECTRONICS SYSTEMS CNTR.
 ***           BOX 746, M.S. 338
 ***           BALTIMORE, MD  21203
 ***
 *** CONVERTED TO MICROSOFT 8 K BASIC 3/16/78 BY JOHN BORDERS
 *** LINE NUMBERS FROM VERSION STREK7 OF 1/12/75 PRESERVED AS
 *** MUCH AS POSSIBLE WHILE USING MULTIPLE STATMENTS PER LINE
 *
 */

/* For `ack -mcpm -fp`, the i80 code was too big.  Make it smaller by
 * removing the game's intro and replacing part of libc. */
#ifdef __i80
#define SMALL
#endif

#ifdef SMALL
#include <stdarg.h>
#include <unistd.h>
#else
#include <stdio.h>
#endif
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <time.h>

#ifndef FALSE
#define FALSE        0
#endif
 
#ifndef TRUE
#define TRUE         ! FALSE
#endif

/* Standard Line Length */
 
#define MAXLEN     255
 
/* Standard Terminal Sizes */
 
#define MAXROW      24
#define MAXCOL      80
 
/* Standard Page Size */
 
#define MAXLINES    66
 
/* Useful typedefs */
 
typedef int bool;
typedef char line[MAXCOL];
typedef char string[MAXLEN];

/* Function Declarations */

void intro(void);
void new_game(void);
void initialize(void);
void new_quadrant(void);
void course_control(void);
void complete_maneuver(void);
void exceed_quadrant_limits(void);
void maneuver_energy(void);
void short_range_scan(void);
void long_range_scan(void);
void phaser_control(void);
void photon_torpedoes(void);
void torpedo_hit(void);
void damage_control(void);
void shield_control(void);
void library_computer(void);
void galactic_record(void);
void status_report(void);
void torpedo_data(void);
void nav_data(void);
void dirdist_calc(void);
void galaxy_map(void);
void end_of_time(void);
void resign_commision(void);
void won_game(void);
void end_of_game(void);
void klingons_move(void);
void klingons_shoot(void);
void repair_damage(void);
void find_empty_place(void);
void insert_in_quadrant(void);
void get_device_name(void);
void string_compare(void);
void quadrant_name(void);
int function_d(int i);
int function_r(void);
void mid_str(char *a, char *b, int x, int y);
int cint(double d);
void compute_vector(void);
void sub1(void);
void sub2(void);
#ifndef SMALL
void showfile(char *filename);
int openfile(char * sFilename, char * sMode);
void closefile(void);
int get_line(char *s);
#endif
void randomize(void);
int get_rand(int iSpread);
double rnd(void);
#ifdef SMALL
#undef atof
#define atof    trek_atof
#define getchar trek_getchar
#define putchar trek_putchar
#define printf  trek_printf
double atof(const char *);
static int getchar(void);
static void putchar(int c);
void printf(const char *fmt, ...);
#endif

/* Global Variables */

int b3;                           /* Starbases in Quadrant */
int b4, b5;                 /* Starbase Location in sector */
int b9;                                 /* Total Starbases */

/* @@@ int c[2][10] = */  /* Used for location and movement */         
int c[3][10] = /* modified to match MS BASIC array indicies */
   {
     { 0 },
     { 0, 0, -1, -1, -1,  0,  1, 1, 1, 0 },
     { 1, 1,  1,  0, -1, -1, -1, 0, 1, 1 }
   };

int d0;                                     /* Docked flag */
int d1;                              /* Damage Repair Flag */
int e;                                   /* Current Energy */
int e0 = 3000;                          /* Starting Energy */
int g[9][9];                                     /* Galaxy */
int g5;                              /* Quadrant name flag */
int k[4][4];                               /* Klingon Data */
int k3;                            /* Klingons in Quadrant */
int k7;                               /* Klingons at start */
int k9;                             /* Total Klingons left */
int n;                       /* Number of secors to travel */
int p;                            /* Photon Torpedoes left */
int p0 = 10;                    /* Photon Torpedo capacity */
int q1, q2;             /* Quadrant Position of Enterprise */
int r1, r2;              /* Temporary Location Corrdinates */
int s;                             /* Current shield value */
int s3;                               /* Stars in quadrant */
int s8;                         /* Quadrant locating index */
int s9 = 200;                             /* Klingon Power */
int t0;                               /* Starting Stardate */
int t9;                                     /* End of time */
int z[9][9];                /* Cumulative Record of Galaxy */
int z3;                     /* string_compare return value */
int z1, z2;                /* Temporary Sector Coordinates */
int z4, z5;              /* Temporary quadrant coordinates */

double a, c1;                   /* Used by Library Computer */
double d[9];                                /* Damage Array */
double d4;         /* Used for computing damage repair time */
double s1, s2;     /* Current Sector Position of Enterprise */
double t;                               /* Current Stardate */
double w1;                                   /* Warp Factor */
double x, y, x1, x2;            /* Navigational coordinates */

char sA[4];                       /* An Object in a Sector */
char sC[7];                                   /* Condition */
char sQ[194];                /* Visual Display of Quadrant */

string sG2;                 /* Used to pass string results */

#ifndef SMALL
FILE *stream;
bool bFlag = FALSE;         /* Prevent multiple file opens */
#endif

void
reads(char* buffer)
{
#ifdef SMALL
  read(0, buffer, sizeof(string));
#else
  fflush(stdout);
  fgets(buffer, sizeof(string), stdin);
#endif
}

/* Main Program */

int
main(void)
{
  intro();

  new_game();

  /* @@@ exit(0);  */ /* causes a warning in C++ */
  return(0);
}

void
intro(void)
{
  string sTemp;

#ifndef SMALL
  printf ("\n\n");
  printf (" *************************************\n");
  printf (" *                                   *\n");
  printf (" *                                   *\n");
  printf (" *      * * Super Star Trek * *      *\n");
  printf (" *                                   *\n");
  printf (" *                                   *\n");
  printf (" *************************************\n\n\n\n\n");

  printf("\nDo you need instructions (y/n): ");

  reads(sTemp);

  if (sTemp[0] == 'y' || sTemp[0] == 'Y')
    showfile("startrek.doc");
#endif /* !SMALL */

  printf ("\n\n\n\n\n\n\n");
  printf("                         ------*------\n");
  printf("         -------------   `---  ------'\n");
  printf("         `-------- --'      / /\n");
  printf("                  \\\\-------  --\n");
  printf("                  '-----------'\n");
  printf("\n       The USS Enterprise --- NCC - 1701\n\n\n");

  randomize();

  t = (get_rand(20) + 20) * 100;
}

void
new_game(void)
{
  string sTemp;

  initialize();

  new_quadrant();

  short_range_scan();

  while(1)
    {
      if (s + e <= 10 && (e < 10 || d[7] < 0))
        {
          printf("\n** Fatal Error **   ");
          printf("You've just stranded your ship in space.\n\n");
          printf("You have insufficient maneuvering energy,");
          printf(" and Shield Control is presently\n");
          printf("incapable of cross circuiting to engine room!!\n\n");
          end_of_time();
        }

      printf("Command? ");

      reads(sTemp);
      printf("\n");

      if (! strncmp(sTemp, "nav", 3))
        course_control();
      else if (! strncmp(sTemp, "srs", 3))
        short_range_scan();
      else if (! strncmp(sTemp, "lrs", 3))
        long_range_scan();
      else if (! strncmp(sTemp, "pha", 3))
        phaser_control();
      else if (! strncmp(sTemp, "tor", 3))
        photon_torpedoes();
      else if (! strncmp(sTemp, "she", 3))
        shield_control();
      else if (! strncmp(sTemp, "dam", 3))
        damage_control();
      else if (! strncmp(sTemp, "com", 3))
        library_computer();
      else if (! strncmp(sTemp, "xxx", 3))
        resign_commision();
      else
    {
          printf("Enter one of the following:\n\n");
      printf("  nav - To Set Course\n");
      printf("  srs - Short Range Sensors\n");
      printf("  lrs - Long Range Sensors\n");
      printf("  pha - Phasers\n");
      printf("  tor - Photon Torpedoes\n");
      printf("  she - Shield Control\n");
      printf("  dam - Damage Control\n");
      printf("  com - Library Computer\n");
      printf("  xxx - Resign Command\n");
      printf("\n");
    }
    }
}

void
initialize(void)
{
  int i, j;
  char sX[2] = "";
  char sX0[4] = "is";

  /* InItialize time */

  /* @@@ t0 = t; */
  t0 = (int)t;
  t9 = 25 + get_rand(10);

  /* Initialize Enterprise */

  d0 = 0;
  e = e0;
  p = p0;
  s = 0;

  q1 = function_r();
  q2 = function_r();
  s1 = (double) function_r();
  s2 = (double) function_r();

  for (i = 1; i <= 8; i++)
    d[i] = 0.0;

  /* Setup What Exists in Galaxy */

  for (i = 1; i <= 8; i++)
    for (j = 1; j <= 8; j++)
      {
        k3 = 0;
        z[i][j] = 0;
        r1 = get_rand(100);
        if (r1 > 98)
          k3 = 3;
        else if (r1 > 95)
          k3 = 2;
        else if (r1 > 80)
          k3 = 1;

        k9 = k9 + k3;
        b3 = 0;

        if (get_rand(100) > 96)
          b3 = 1;

        b9 = b9 + b3;

        g[i][j] = k3 * 100 + b3 * 10 + function_r();
      }

  if (k9 > t9)
    t9 = k9 + 1;

  if (b9 == 0)
    {
      if (g[q1][q2] < 200)
        {
          g[q1][q2] = g[q1][q2] + 100;
          k9++;
        }

      g[q1][q2] = g[q1][q2] + 10;
      b9++;

      q1 = function_r();
      q2 = function_r();
    }

  k7 = k9;

  if (b9 != 1)
    {
      strcpy(sX, "s");
      strcpy(sX0, "are");
    }

  printf("Your orders are as follows:\n\n");
  printf("   Destroy the %d Klingon warships which have invaded\n", k9);
  printf(" the galaxy before they can attack Federation Headquarters\n");
  printf(" on stardate %d. This gives you %d days. There %s\n",
    t0 + t9, t9, sX0);
  printf(" %d starbase%s in the galaxy for resupplying your ship.\n\n",
    b9, sX);

  printf("Hit any key to accept command. ");
  getchar();
}

void
new_quadrant(void)
{
  int i;

  z4 = q1;
  z5 = q2;
  k3 = 0;
  b3 = 0;
  s3 = 0;
  g5 = 0; 
  d4 = (double) get_rand(100) / 100 / 50;
  z[q1][q2] = g[q1][q2];

  if (q1 >= 1 && q1 <= 8 && q2 >= 1 && q2 <= 8)
    {
      quadrant_name();

      if (t0 != t)
        printf("Now entering %s quadrant...\n\n", sG2);
      else
        {
          printf("\nYour mission begins with your starship located\n");
          printf("in the galactic quadrant %s.\n\n", sG2);
        }
    }

  /* @@@ k3 = g[q1][q2] * .01; */
  k3 = (int)(g[q1][q2] * .01);
  /* @@@ b3 = g[q1][q2] * .1 - 10 * k3; */
  b3 = (int)(g[q1][q2] * .1 - 10 * k3);
  s3 = g[q1][q2] - 100 * k3 - 10 * b3;

  if (k3 > 0)
    {
      printf("Combat Area  Condition Red\n");

      if (s < 200)
        printf("Shields Dangerously Low\n");
    }

  for (i = 1; i <= 3; i++)
    {
      k[i][1] = 0;
      k[i][2] = 0;
      k[i][3] = 0;
    }

  for (i = 0; i <= 192; i++)
    sQ[i] = ' ';

  sQ[193] = '\0';

  /* Position Enterprise, then Klingons, Starbases, and stars */

  strcpy(sA, "<*>");
  /* @@@ z1 = cint(s1); */
  z1 = (int)s1;
  /* @@@ z2 = cint(s2); */
  z2 = (int)s2;
  insert_in_quadrant();

  if (k3 > 0)
    {
      for (i = 1; i <= k3; i++)
        {
          find_empty_place();

          strcpy(sA, "+K+");
          z1 = r1;
          z2 = r2;
          insert_in_quadrant();

          k[i][1] = r1;
          k[i][2] = r2;
          k[i][3] = 100 + get_rand(200);
        }
    }

  if (b3 > 0)
    {
      find_empty_place();

      strcpy(sA, ">!<");
      z1 = r1;
      z2 = r2;
      insert_in_quadrant();

      b4 = r1;
      b5 = r2;
    }

  for (i = 1; i <= s3; i++)
    {
      find_empty_place();

      strcpy(sA, " * ");
      z1 = r1;
      z2 = r2;
      insert_in_quadrant();
    }
}

void
course_control(void)
{
  register i;
  /* @@@ int c2, c3, q4, q5; */
  int q4, q5;
  string sTemp;
  double c1;
  char sX[4] = "8";

  printf("Course (0-9): ");

  reads(sTemp);

  printf("\n");

  c1 = atof(sTemp);
 
  if (c1 == 9.0)
    c1 = 1.0;

  if (c1 < 0 || c1 > 9.0)
    {
      printf("Lt. Sulu roports:\n");
      printf("  Incorrect course data, sir!\n\n");
      return;
    }

  if (d[1] < 0.0)
    strcpy(sX, "0.2");

  printf("Warp Factor (0-%s): ", sX);

  reads(sTemp);

  printf("\n");

  w1 = atof(sTemp);

  if (d[1] < 0.0 && w1 > 0.21)
    {
      printf("Warp Engines are damaged. ");
      printf("Maximum speed = Warp 0.2.\n\n");
      return;
    }

  if (w1 <= 0.0)
    return;

  if (w1 > 8.1)
    {
      printf("Chief Engineer Scott reports:\n");
      printf("  The engines won't take warp %4.1f!\n\n", w1);
      return;
    }

  n = cint(w1 * 8.0); /* @@@ note: this is a real round in the original basic */
  
  if (e - n < 0)
    {
      printf("Engineering reports:\n");
      printf("  Insufficient energy available for maneuvering");
      printf(" at warp %4.1f!\n\n", w1);

      if (s >= n && d[7] >= 0.0)
        {
          printf("Deflector Control Room acknowledges:\n");
          printf("  %d units of energy presently deployed to shields.\n", s);
        }

      return;
    }

  klingons_move();

  repair_damage();

  strcpy(sA, "   ");
  /* @@@ z1 = cint(s1); */
  z1 = (int)s1;
  /* @@@ z2 = cint(s2); */
  z2 = (int)s2;
  insert_in_quadrant();

  /* @@@ c2 = cint(c1); */
  /* @@@ c3 = c2 + 1; */

  /* @@@ x1 = c[0][c2] + (c[0][c3] - c[0][c2]) * (c1 - c2); */
  /* @@@ x2 = c[1][c2] + (c[1][c3] - c[1][c2]) * (c1 - c2); */

  x1 = c[1][(int)c1] + (c[1][(int)c1 + 1] - c[1][(int)c1]) * (c1 - (int)c1);
  x2 = c[2][(int)c1] + (c[2][(int)c1 + 1] - c[2][(int)c1]) * (c1 - (int)c1);

  x = s1;
  y = s2;
  q4 = q1;
  q5 = q2;

  for (i = 1; i <= n; i++)
    {
      s1 = s1 + x1;
      s2 = s2 + x2;

      /* @@@ z1 = cint(s1); */
      z1 = (int)s1;
      /* @@@ z2 = cint(s2); */
      z2 = (int)s2;

      if (z1 < 1 || z1 >= 9 || z2 < 1 || z2 >= 9)
        {
          exceed_quadrant_limits();
          complete_maneuver();
          return;
        }

      string_compare();

      if (z3 != 1) /* Sector not empty */
        {
          s1 = s1 - x1;
          s2 = s2 - x2;
          printf("Warp Engines shut down at sector ");
          printf("%d, %d due to bad navigation.\n\n", z1, z2);
          i = n + 1;
        }
    }

  complete_maneuver();
}

void
complete_maneuver(void)
{
  double t8;

  strcpy(sA, "<*>");
  /* @@@ z1 = cint(s1); */
  z1 = (int)s1;
  /* @@@ z2 = cint(s2); */
  z2 = (int)s2;
  insert_in_quadrant();

  maneuver_energy();

  t8 = 1.0;

  if (w1 < 1.0)
    t8 = w1;

  t = t + t8;

  if (t > t0 + t9)
    end_of_time();

  short_range_scan();
}

void
exceed_quadrant_limits(void)
{
  int x5 = 0;   /* Outside galaxy flag */

  /* @@@ x = (8 * (q1 - 1)) + x + (n * x1); */
  x = (8 * q1) + x + (n * x1);
  /* @@@ y = (8 * (q2 - 1)) + y + (n * x2); */
  y = (8 * q2) + y + (n * x2);

  /* @@@ q1 = cint(x / 8.0); */
  q1 = (int)(x / 8.0);
  /* @@@ q2 = cint(y / 8.0); */
  q2 = (int)(y / 8.0);
  
  /* @@@ s1 = x - ((q1 - 1) * 8); */
  s1 = x - (q1 * 8);
  /* @@@ s2 = y - ((q2 - 1) * 8); */
  s2 = y - (q2 * 8);

  /* @@@ if (cint(s1) == 0) */
  if ((int)s1 == 0)
    {
      q1 = q1 - 1;
      s1 = s1 + 8.0;
    }

  /* @@@ if (cint(s2) == 0) */
  if ((int)s2 == 0)
    {
      q2 = q2 - 1;
      s2 = s2 + 8.0;
    }

  /* check if outside galaxy */

  if (q1 < 1)
    {
      x5 = 1;
      q1 = 1;
      s1 = 1.0;
    }

  if (q1 > 8)
    {
      x5 = 1;
      q1 = 8;
      s1 = 8.0;
    }

  if (q2 < 1)
    {
      x5 = 1;
      q2 = 1;
      s2 = 1.0;
    }

  if (q2 > 8)
    {
      x5 = 1;
      q2 = 8;
      s2 = 8.0;
    }

  if (x5 == 1)
    {
      printf("LT. Uhura reports:\n");
      printf("  Message from Starfleet Command:\n\n");
      printf("  Permission to attempt crossing of galactic perimeter\n");
      printf("  is hereby *denied*. Shut down your engines.\n\n");
      printf("Chief Engineer Scott reports:\n");
      /* @@@ printf("  Warp Engines shut down at sector %d, ", cint(s1)); */
      printf("  Warp Engines shut down at sector %d, ", (int)s1);
      /* @@@ printf("%d of quadrant %d, %d.\n\n", cint(s2), q1, q2); */
      printf("%d of quadrant %d, %d.\n\n", (int)s2, q1, q2);
    }
  /* else 
     new_quadrant(); @@@ this causes bugs when bouncing off galaxy walls.
                         basically, if you bounce very far, your quadrant contents
                         won't match your LRS.  Cool huh? */


  maneuver_energy();

  /* this section has a different order in the original.
  t = t + 1;
  
  if (t > t0 + t9)
    end_of_time();
  */

  if (t > t0 + t9)
    end_of_time();

  /* @@@ what does this do?? It's in the original.
  if (8 * q1 + q2 = 8 * q4 + q5) 
    { 
      complete_maneuver();
    }
  */

  t = t + 1;

  new_quadrant();
}

void
maneuver_energy(void)
{
  e = e - n - 10;

  if (e >= 0)
    return;

  printf("Shield Control supplies energy to complete maneuver.\n\n");

  s = s + e;
  e = 0;

  if (s <= 0)
    s = 0;
}

void
short_range_scan(void)
{
  register i, j;

  strcpy(sC, "GREEN");

  if (e < e0 * .1)
    strcpy(sC, "YELLOW");

  if (k3 > 0)
    strcpy(sC, "*RED*");

  /* @@@ need to clear the docked flag here */
  d0 = 0;

  /* @@@ for (i = s1 - 1; i <= s1 + 1; i++) */
  for (i = (int)(s1 - 1); i <= (int)(s1 + 1); i++)
    /* @@@ for (j = s2 - 1; j <= s2 + 1; j++) */
    for (j = (int)(s2 - 1); j <= (int)(s2 + 1); j++)
      if (i >= 1 && i <= 8 && j >= 1 && j <= 8)
        {
          strcpy(sA, ">!<");
          z1 = i;
          z2 = j;
          string_compare();
          if (z3 == 1)
            {
              d0 = 1;
              strcpy(sC, "DOCKED");
              e = e0;
              p = p0;
              printf("Shields dropped for docking purposes.\n");
              s = 0;
            }
        }
          
  if (d[2] < 0.0)
    {
      printf("\n*** Short Range Sensors are out ***\n");
      return;
    }

  printf("------------------------\n");
  for (i = 0; i < 8; i++)
    {
      for (j = 0; j < 24; j++)
        putchar(sQ[i * 24 + j]); 

      if (i == 0)
    printf("    Stardate            %d\n", (int) t);
      if (i == 1)
    printf("    Condition           %s\n", sC);
      if (i == 2)
    printf("    Quadrant            %d, %d\n", q1, q2);
      if (i == 3)
    /* @@@ printf("    Sector              %d, %d\n", cint(s1), cint(s2)); */
    printf("    Sector              %d, %d\n", (int)s1, (int)s2);
      if (i == 4)
    printf("    Photon Torpedoes    %d\n", p);
      if (i == 5)
    printf("    Total Energy        %d\n", e + s);
      if (i == 6)
    printf("    Shields             %d\n", s);
      if (i == 7)
    printf("    Klingons Remaining  %d\n", k9);
    }
  printf("------------------------\n\n");

  return;
}

void
long_range_scan(void)
{
  register i, j;

  if (d[3] < 0.0)
    {
      printf("Long Range Sensors are inoperable.\n");
      return;
    }

  printf("Long Range Scan for Quadrant %d, %d\n\n", q1, q2);

  for (i = q1 - 1; i <= q1 + 1; i++)
    {
      printf("--------------------\n:");
      for (j = q2 - 1; j <= q2 + 1; j++)
        if (i > 0 && i <= 8 && j > 0 && j <= 8)
          {
            z[i][j] = g[i][j];
            printf(" %3.3d :", z[i][j]);
          }
        else
          printf(" *** :");
      printf("\n");
    }

    printf("--------------------\n\n");
}

void
phaser_control(void)
{
  register i;
  int iEnergy;
  int h1, h;
  string sTemp;

  if (d[4] < 0.0)
    {
      printf("Phasers Inoperative\n\n");
      return;
    }

  if (k3 <= 0)
    {
      printf("Science Officer Spock reports:\n");
      printf("  'Sensors show no enemy ships in this quadrant'\n\n");
      return;
    }

  if (d[8] < 0.0)
    /* @@@ printf("Computer failure happers accuracy.\n"); */
    printf("Computer failure hampers accuracy.\n");

  printf("Phasers locked on target;\n");
  printf("Energy available = %d units\n\n", e);

  printf("Number of units to fire: ");

  reads(sTemp);

  printf("\n");

  iEnergy = atoi(sTemp);

  if (iEnergy <= 0)
    return;

  if (e - iEnergy < 0)
    {
      printf("Not enough energy available.\n\n");
      return;
    }

  e = e - iEnergy;

  if (d[8] < 0.0)
    /* @@@ iEnergy = iEnergy * rnd(); */
    iEnergy = (int)(iEnergy * rnd());

  h1 = iEnergy / k3;

  for (i = 1; i <= 3; i++)
    {
      if (k[i][3] > 0)
        {
          /* @@@ h = (h1 / function_d(0) * (rnd() + 2)); */
          h = (int)(h1 / function_d(0) * (rnd() + 2));
          if (h <= .15 * k[i][3])
            {
              printf("Sensors show no damage to enemy at ");
              printf("%d, %d\n\n", k[i][1], k[i][2]);
            }
          else
            {
              k[i][3] = k[i][3] - h;
              printf("%d unit hit on Klingon at sector ", h);
              printf("%d, %d\n", k[i][1], k[i][2]);
              if (k[i][3] <= 0)
                {
                  printf("*** Klingon Destroyed ***\n\n");
                  k3--;
                  k9--;
                  z1 = k[i][1];
                  z2 = k[i][2];
                  strcpy(sA, "   ");
                  insert_in_quadrant();
                  k[i][3] = 0;
                  g[q1][q2] = g[q1][q2] - 100;
                  z[q1][q2] = g[q1][q2];
                  if (k9 <= 0)
                    won_game();
                }
              else
                /* @@@ printf("\n"); */
                printf("   (Sensors show %d units remaining.)\n\n", k[i][3]);
            }
        }
    }

  klingons_shoot();
}

void
photon_torpedoes(void)
{
  /* @@@ int c2, c3, x3, y3, x5; */
  int x3, y3, x5;
  string sTemp;
  double c1;

  if (p <= 0)
    {
      printf("All photon torpedoes expended\n");
      return;
    }

  if (d[5] < 0.0)
    {
      printf("Photon Tubes not operational\n");
      return;
    }

  printf("Course (0-9): ");

  reads(sTemp);

  printf("\n");

  c1 = atof(sTemp);

  if (c1 == 9.0)
    c1 = 1.0;

  /* @@@ if (c1 < 0 || c1 > 9.0) */
  if (c1 < 1.0 || c1 > 9.0)
    {
      printf("Ensign Chekov roports:\n");
      printf("  Incorrect course data, sir!\n\n");
      return;
    }

  e = e - 2;
  p--;

  /* @@@ c2 = cint(c1); */
  /* @@@ c3 = c2 + 1; */

  /* @@@ x1 = c[0][c2] + (c[0][c3] - c[0][c2]) * (c1 - c2); */
  /* @@@ x2 = c[1][c2] + (c[1][c3] - c[1][c2]) * (c1 - c2); */

  x1 = c[1][(int)c1] + (c[1][(int)c1 + 1] - c[1][(int)c1]) * (c1 - (int)c1);
  x2 = c[2][(int)c1] + (c[2][(int)c1 + 1] - c[2][(int)c1]) * (c1 - (int)c1);

  x = s1 + x1;
  y = s2 + x2;

  x3 = cint(x); /* @@@ note: this is a true integer round in the MS BASIC version */
  y3 = cint(y); /* @@@ note: this is a true integer round in the MS BASIC version */

  x5 = 0;

  printf("Torpedo Track:\n");

  while (x3 >= 1 && x3 <= 8 && y3 >= 1 && y3 <= 8)
    {
      printf("    %d, %d\n", x3, y3);

      strcpy(sA, "   ");
      z1 = x3;
      z2 = y3;

      string_compare();

      if (z3 == 0)
        {
          torpedo_hit();
          klingons_shoot();
          return;
        }

      x = x + x1;
      y = y + x2;

      x3 = cint(x); /* @@@ note: this is a true integer round in the MS BASIC version */
      y3 = cint(y); /* @@@ note: this is a true integer round in the MS BASIC version */
    }

  printf("Torpedo Missed\n\n");

  klingons_shoot();
}

void
torpedo_hit(void)
{
  int i, x3, y3;

  x3 = cint(x); /* @@@ note: this is a true integer round in the MS BASIC version */
  y3 = cint(y); /* @@@ note: this is a true integer round in the MS BASIC version */

  z3 = 0;

  strcpy(sA, " * ");
  string_compare();

  if (z3 == 1)
    {
      printf("Star at %d, %d absorbed torpedo energy.\n\n", x3, y3);
      return;
    }

  strcpy(sA, "+K+");
  string_compare();

  if (z3 == 1)
    {
      printf("*** Klingon Destroyed ***\n\n");
      k3--;
      k9--;

      if (k9 <= 0)
        won_game();

      for (i=0; i<=3; i++)
        if (x3 == k[i][1] && y3 == k[i][2])
          k[i][3] = 0;
    }

  strcpy(sA, ">!<");
  string_compare();

  if (z3 == 1)
    {
      printf("*** Starbase Destroyed ***\n");
      b3--;
      b9--;

      if (b9 <= 0 && k9 <= t - t0 - t9)
        {
          printf("That does it, Captain!!");
          printf("You are hereby relieved of command\n");
          printf("and sentanced to 99 stardates of hard");
          printf("labor on Cygnus 12!!\n");
          resign_commision();
        }

      printf("Starfleet Command reviewing your record to consider\n");
      printf("court martial!\n\n");

      d0 = 0;    /* Undock */
    }

  z1 = x3;
  z2 = y3;
  strcpy(sA,"   ");
  insert_in_quadrant();

  g[q1][q2] = (k3 * 100) + (b3 * 10) + s3;
  z[q1][q2] = g[q1][q2];
}

void
damage_control(void)
{ 
  int a1;
  double d3 = 0.0;
  register i;

  if (d[6] < 0.0)
    {
      printf("Damage Control report not available.\n");

      if (d0 == 0)
        return;

      d3 = 0.0;
      for (i = 1; i <= 8; i++)
        if (d[i] < 0.0)
          d3 = d3 + .1;

      if (d3 == 0.0)
        return;

      d3 = d3 + d4;
      if (d3 >= 1.0)
        d3 = 0.9;

      printf("\nTechnicians standing by to effect repairs to your");
      /* @@@ printf("ship; Will you authorize the repair order (Y/N)? "); */
      printf("ship;\nEstimated time to repair: %4.2f stardates.\n", d3);
      printf("Will you authorize the repair order (Y/N)? ");

      a1 = getchar();

      if (a1 == 'Y' || a1 == 'y')
        {
          for (i = 1; i <= 8; i++)
            if (d[i] < 0.0)
              d[i] = 0.0;

          t = t + d3 + 0.1;
        }
    }

  printf("Device            State of Repair\n");

  for (r1 = 1; r1 <= 8; r1++)
    {
      get_device_name();
      printf(sG2);
      /* @@@ for (i = 1; i < 25 - strlen(sG2); i++) */
      for (i = 1; i < 25 - (int)strlen(sG2); i++)
      printf(" ");
      /* @@@ printf("%4.1f\n", d[r1]); */
      printf("%4.2f\n", d[r1]);
    }

  printf("\n");
} 

void
shield_control(void)
{
  int i;
  string sTemp;

  if (d[7] < 0.0)
    {
      printf("Shield Control inoperable\n");
      return;
    }

  printf("Energy available = %d\n\n", e + s);

  printf("Input number of units to shields: ");

  reads(sTemp);

  printf("\n");

  i = atoi(sTemp);

  if (i < 0 || s == i)
    {
      printf("<Shields Unchanged>\n\n");
      return;
    }

  if (i >= e + s)
    {
      printf("Shield Control Reports:\n");
      printf("  'This is not the Federation Treasury.'\n");
      printf("<Shields Unchanged>\n\n");
      return;
    }

  e = e + s - i;
  s = i;

  printf("Deflector Control Room report:\n");
  printf("  'Shields now at %d units per your command.'\n\n", s);
}

void
library_computer(void)
{
  string sTemp;

  if (d[8] < 0.0)
    {
      printf("Library Computer inoperable\n");
      return;
    }

  printf("Computer active and awating command: ");

  reads(sTemp);
  printf("\n");

  if (! strncmp(sTemp, "0", 1))
    galactic_record();
  else if (! strncmp(sTemp, "1", 1))
    status_report();
  else if (! strncmp(sTemp, "2", 1))
    torpedo_data();
  else if (! strncmp(sTemp, "3", 1))
    nav_data();
  else if (! strncmp(sTemp, "4", 1))
    dirdist_calc();
  else if (! strncmp(sTemp, "5", 1))
    galaxy_map();
  else
    {
      printf("Functions available from Library-Computer:\n\n");
      printf("   0 = Cumulative Galactic Record\n");
      printf("   1 = Status Report\n");
      printf("   2 = Photon Torpedo Data\n");
      printf("   3 = Starbase Nav Data\n");
      printf("   4 = Direction/Distance Calculator\n");
      printf("   5 = Galaxy 'Region Name' Map\n\n");
    }
}

void
galactic_record(void)
{
  int i, j;

  printf("\n     Computer Record of Galaxy for Quadrant %d,%d\n\n", q1, q2);
  printf("     1     2     3     4     5     6     7     8\n");

  for (i = 1; i <= 8; i++)
  { 
    printf("   ----- ----- ----- ----- ----- ----- ----- -----\n");

    printf("%d", i);

    for (j = 1; j <= 8; j++)
    {
      printf("   ");

      if (z[i][j] == 0)
        printf("***");
      else
        printf("%3.3d", z[i][j]);
    }

    printf("\n");
  }

  printf("   ----- ----- ----- ----- ----- ----- ----- -----\n\n");
}

void
status_report(void)
{
  char sX[2] = "";

  printf("   Status Report:\n\n");

  if (k9 > 1)
    strcpy(sX, "s");

  printf("Klingon%s Left: %d\n", sX, k9);

  printf("Mission must be completed in %4.1f stardates\n",
    /* @@@ .1 * cint((t0 + t9 - t) * 10)); */
    .1 * (int)((t0 + t9 - t) * 10));

  if (b9 < 1)
  {
    printf("Your stupidity has left you on your own in the galaxy\n");
    printf(" -- you have no starbases left!\n");
  }
  else
  {  
    strcpy(sX, "s");
    if (b9 < 2)
      strcpy(sX, "");

    printf("The Federation is maintaining %d starbase%s in the galaxy\n",
      b9, sX);
  }

  printf("\n");
}

void
torpedo_data(void)
{
  int i;
  char sX[2] = "";

  if (k3 <= 0)
  {
    printf("Science Officer Spock reports:\n");
    printf("  'Sensors show no enemy ships in this quadrant.'\n\n");
    return;
  }

  if (k3 > 1)
    strcpy(sX, "s");
 
  printf("From Enterprise to Klingon battlecriuser%s:\n\n", sX);

  for (i = 1; i <= 3; i++)
  {
    if (k[i][3] > 0)
    {
      w1 = k[i][1];
      x  = k[i][2];
      c1 = s1;
      a  = s2;

      compute_vector();
    }
  }
}

void
nav_data(void)
{
  if (b3 <= 0)
  {
    printf("Mr. Spock reports,\n");
    printf("  'Sensors show no starbases in this quadrant.'\n\n");
    return;
  }

  w1 = b4;
  x  = b5;
  c1 = s1;
  a  = s2;

  compute_vector();
}

void
dirdist_calc(void)
{
  string sTemp;

  printf("Direction/Distance Calculator\n\n");
  printf("You are at quadrant %d,%d sector %d,%d\n\n", q1, q2,
    /* @@@ cint(s1), cint(s2)); */
    (int)s1, (int)s2);
    
  printf("Please enter initial X coordinate: ");
  reads(sTemp);
  c1 = atoi(sTemp);

  printf("Please enter initial Y coordinate: ");
  reads(sTemp);
  a = atoi(sTemp);

  printf("Please enter final X coordinate: ");
  reads(sTemp);
  w1 = atoi(sTemp);

  printf("Please enter final Y coordinate: ");
  reads(sTemp);
  x = atoi(sTemp);

  compute_vector();
}

void
galaxy_map(void)
{
  int i, j, j0;

  g5 = 1;

  printf("\n                   The Galaxy\n\n");
  printf("    1     2     3     4     5     6     7     8\n");

  for (i = 1; i <= 8; i++)
  {
    printf("  ----- ----- ----- ----- ----- ----- ----- -----\n");

    printf("%d ", i);

    z4 = i;
    z5 = 1;
    quadrant_name();

    j0 = (int)(11 - (strlen(sG2) / 2));

    for (j = 0; j < j0; j++)
      printf(" ");

    printf(sG2);

    for (j = 0; j < j0; j++)
      printf(" ");

    if (! (strlen(sG2) % 2))
      printf(" ");

    z5 = 5;
    quadrant_name();

    j0 = (int)(12 - (strlen(sG2) / 2));

    for (j = 0; j < j0; j++)
      printf(" ");

    printf(sG2); 
   
    printf("\n");
  }

  printf("  ----- ----- ----- ----- ----- ----- ----- -----\n\n");

}

void
compute_vector(void)
{
  x = x - a;
  a = c1 - w1;

  if (x <= 0.0)
  {
    if (a > 0.0)
    {    
      c1 = 3.0;
      sub2();
      return;
    }
    else
    {
      c1 = 5.0;
      sub1();
      return;
    }
  }
  else if (a < 0.0)
  {
    c1 = 7.0;
    sub2();
    return;
  }
  else
  {
    c1 = 1.0;
    sub1();
    return;
  }
}

void
sub1(void)
{
  x = fabs(x);
  a = fabs(a);

  if (a <= x)
    printf("  DIRECTION = %4.2f\n", c1 + (a / x));
  else
    printf("  DIRECTION = %4.2f\n", c1 + (((a * 2) - x) / a));

  printf("  DISTANCE = %4.2f\n\n", (x > a) ? x : a);
}

void
sub2(void)
{
  x = fabs(x);
  a = fabs(a);

  if (a >= x)
    printf("  DIRECTION = %4.2f\n", c1 + (x / a));
  else
    /* @@@ printf("  DIRECTION = %4.2f\n\n", c1 + (((x * 2) - a) / x)); */
    printf("  DIRECTION = %4.2f\n", c1 + (((x * 2) - a) / x));

  /* @@@ printf("  DISTANCE = %4.2f\n", (x > a) ? x : a); */
  printf("  DISTANCE = %4.2f\n\n", (x > a) ? x : a);
}

void
ship_destroyed(void)
{
  printf("The Enterprise has been destroyed. ");
  printf("The Federation will be conquered.\n\n");

  end_of_time();
}

void
end_of_time(void)
{
  printf("It is stardate %d.\n\n", (int) t);

  resign_commision();
}

void
resign_commision(void)
{
  printf("There were %d Klingon Battlecruisers left at the", k9);
  printf(" end of your mission.\n\n");

  end_of_game();
}

void
won_game(void)
{
  printf("Congradulations, Captain!  The last Klingon Battle Cruiser\n");
  printf("menacing the Federation has been destoyed.\n\n");
 
  if (t - t0 > 0)
    printf("Your efficiency rating is %4.2f\n", 1000 * pow(k7 / (t - t0), 2));

  end_of_game();
}

void
end_of_game(void)
{
  string sTemp;

  if (b9 > 0)
    {
      printf("The Federation is in need of a new starship commander");
      printf(" for a similar mission.\n");
      printf("If there is a volunteer, let him step forward and");
      printf(" enter 'aye': ");

      reads(sTemp);
      printf("\n");

      if (! strncmp(sTemp, "aye", 3))
        new_game();
    }

  exit(0);
}

void
klingons_move(void)
{
  int i;

  for (i = 1; i <= 3; i++)
    {
      if (k[i][3] > 0)
        {
          strcpy(sA, "   ");
          z1 = k[i][1];
          z2 = k[i][2];
          insert_in_quadrant();

          find_empty_place();

          k[i][1] = z1;
          k[i][2] = z2;
          strcpy(sA, "+K+");
          insert_in_quadrant();
        }
    }

  klingons_shoot();
}

void
klingons_shoot(void)
{
  int h, i;

  if (k3 <= 0)
    return;

  if (d0 != 0)
    {
      printf("Starbase shields protect the Enterprise\n\n");
      return;
    }

  for (i = 1; i <= 3; i++)
    {
      if (k[i][3] > 0)
        {
          h = (int) ((k[i][3] / function_d(i)) * (2 + rnd()));
          s = s - h;
          /* @@@ k[i][3] = k[i][3] / (3 + rnd()); */
          k[i][3] = (int)(k[i][3] / (3 + rnd()));

          printf("%d unit hit on Enterprise from sector ", h);
          printf("%d, %d\n", k[i][1], k[i][2]);

              if (s <= 0)
                {
                  printf("\n");
                  ship_destroyed();
                }

              printf("    <Shields down to %d units>\n\n", s);

          if (h >= 20)
            {
              if (rnd() <= 0.6 || (h / s) > 0.2)
                {
                  r1 = function_r();
                  d[r1] = d[r1] - (h / s) - (0.5 * rnd());

                  get_device_name();

                  printf("Damage Control reports\n");
                  printf("   '%s' damaged by hit\n\n", sG2);
                }
            }
        }
    }
} 

void
repair_damage(void)
{
  int i;
  double d6;              /* Repair Factor */

  d6 = w1;

  if (w1 >= 1.0)
    d6 = w1 / 10;

  for (i = 1; i <= 8; i++)
    {
      if (d[i] < 0.0)
        {
          d[i] = d[i] + d6;
          if (d[i] > -0.1 && d[i] < 0)
            d[i] = -0.1;
          else if (d[i] >= 0.0)
            {
              if (d1 != 1)
                d1 = 1;

              printf("Damage Control report:\n");
              r1 = i;
              get_device_name();
              printf("    %s repair completed\n\n", sG2);
            }
        }
    }

  if (rnd() <= 0.2)
    {
      r1 = function_r();

      if (rnd() < .6)
        {
          d[r1] = d[r1] - (rnd() * 5.0 + 1.0);
          printf("Damage Control report:\n");
          get_device_name();
          printf("    %s damaged\n\n", sG2);
        }
      else
        {
          d[r1] = d[r1] + (rnd() * 3.0 + 1.0);
          printf("Damage Control report:\n");
          get_device_name();
          printf("    %s state of repair improved\n\n", sG2);
        }
    }
}

/* Misc Functions and Subroutines */

void
find_empty_place(void)
{
  /* @@@ while (z3 == 0) this is a nasty one.*/
  do
    {
      r1 = function_r();
      r2 = function_r();

      strcpy(sA, "   ");

      z1 = r1;
      z2 = r2;

      string_compare();
    } while (z3 == 0);

  z3 = 0;
}

void
insert_in_quadrant(void)
{
  int i, j = 0;

  /* @@@ s8 = ((z2 - 1) * 3) + ((z1 - 1) * 24) + 1; */
  s8 = ((int)(z2 - 0.5) * 3) + ((int)(z1 - 0.5) * 24) + 1;

  for (i = s8 - 1; i <= s8 + 1; i++)
    sQ[i] = sA[j++];

  return;
}

void
get_device_name(void)
{
  static char * device_name[] = {
    "", "Warp Engines","Short Range Sensors","Long Range Sensors",
    "Phaser Control","Photon Tubes","Damage Control","Shield Control",
    "Library-Computer"};

  if (r1 < 0 || r1 > 8)
    r1 = 0;

  strcpy(sG2, device_name[r1]);

  return;
}

void
string_compare(void)
{
  int i;
  char sB[4];

  z1 = (int)(z1 + 0.5);
  z2 = (int)(z2 + 0.5);

  s8 = ((z2 - 1) * 3) + ((z1 - 1) * 24) + 1;

  mid_str(sB, sQ, s8, 3);

  i = strncmp(sB, sA, 3);

  if (i == 0)
    z3 = 1;
  else
    z3 = 0;

  return;
}

void
quadrant_name(void)
{
  static char * quad_name[] = {"","Antares","Rigel","Procyon","Vega",
    "Canopus","Altair","Sagittarius","Pollux","Sirius","Deneb","Capella",
    "Betelgeuse","Aldebaran","Regulus","Arcturus","Spica"};

  static char * sect_name[] = {""," I"," II"," III"," IV"};

  if (z4 < 1 || z4 > 8 || z5 < 1 || z5 > 8)
    strcpy(sG2, "Unknown");

  if (z5 <= 4)
    strcpy(sG2, quad_name[z4]);
  else
    strcpy(sG2, quad_name[z4+8]);

  if (g5 != 1)
    {
      if (z5 > 4)
      z5 = z5 - 4;
      strcat(sG2, sect_name[z5]);
    }

  return;
}

int
function_d(int i)
{
  int j;

  /* @@@ j = sqrt(pow((k[i][1] - s1), 2) + pow((k[i][2] - s2), 2)); */
  j = (int)sqrt(pow((k[i][1] - s1), 2) + pow((k[i][2] - s2), 2));

  return j;
}

int
function_r(void)
{
  return(get_rand(8));
}

void
mid_str(char *a, char *b, int x, int y)
{
  --x;
  y += x;

  /* @@@ while (x < y && x <= strlen(b)) */
  while (x < y && x <= (int)strlen(b))
    *a++ = *(b + x++);

  *a = '\0';
}

/* Round off floating point numbers instead of truncating */

int
cint (double d)
{
  int i;

  i = (int) (d + 0.5);

  return(i);
}

#ifndef SMALL
void
showfile(char *filename)
{
  line lBuffer;
  int iRow = 0;

  if (openfile(filename, "r") != 0)
    return;

  while (get_line(lBuffer) != 0)
    {
      printf(lBuffer);
      
      if (iRow++ > MAXROW - 3)
        {
          getchar();
          iRow = 0;
        }
    }

  closefile();
}

int
openfile(char * sFilename, char * sMode)
{
  if (bFlag || (stream = fopen (sFilename, sMode)) == NULL)
    {
      fprintf (stderr, "\nError - Unable to open file: %s.\n\n", sFilename);
      return 1;
    }

  bFlag = TRUE;

  return 0;
}

void
closefile(void)
{
  if (! bFlag)
    fclose(stream);

  bFlag = FALSE;
}

int
get_line(char *s)
{
  fflush(stdout);
  if (fgets(s, MAXCOL, stream) == NULL)
    return(0);
  else
    return(strlen(s));
}
#endif /* !SMALL */

/* Seed the randomizer with the timer */
void
randomize(void)
{
  time_t timer;

  srand ((unsigned) time (&timer));
}

/* Returns an integer from 1 to iSpread */
int
get_rand(int iSpread)
{
  return((rand() % iSpread) + 1);
}

double
rnd(void)
{
  double d;

  d = rand() / (double) RAND_MAX;
  
  return(d);
}

#ifdef SMALL
/* These are small but incomplete replacements for functions in libc.
 * Local variables are static for smaller i80 code. */

double
atof(const char *str)
{
  static double d;
  static char n, prec;

  d = 0.0;
  n = prec = 0; /* Forget to skip whitespace before number */
  if (*str == '-') { n = 1; str++; }
  for (;;)
    {
      if (*str >= '0' && *str <= '9')
        {
          d = 10.0 * d + (double)(*str - '0');
          if (prec != 0) prec++;
        }
      else if (*str == '.')
        prec++;
      else
        break; /* Forget to parse exponent like "e10" */
      str++;
    }
  while (prec > 1) { d /= 10.0; prec--; }
  return n ? -d : d;
}

static int
getchar(void)
{
  static unsigned char c[2]; /* CP/M read() needs 2 bytes */

  if (read(0, c, 2) > 0)
    return c[0];
  else
    return -1;
}

static void
putchar(int c)
{
  write(1, &c, 1);
}

struct printf_buf {
  char  p_buf[13];
  char  p_len;
  char *p_str;
};

static struct printf_buf pfb;

static void
pfb_put(int c)
{
  if (pfb.p_str != pfb.p_buf)
    {
      pfb.p_str--;
      *pfb.p_str = c; /* Prepend character to buffer */
      pfb.p_len++;
    }
  else
    pfb.p_len = 0; /* No room in buffer; force empty string */
}

void
printf(const char *fmt, ...)
{
  static va_list ap;
  static const char *s;

  va_start(ap, fmt);
  while (*fmt != '\0')
    {
      if (*fmt != '%')
        {
          s = fmt;
          do { s++; } while ( *s != '\0' && *s != '%');
          write(1, fmt, s - fmt);
          fmt = s;
        }
      if (*fmt == '%')
        {
          static char prec, width;

          fmt++; /* Pass '%' */
          /* Read optional width.prec, as 4.2 in "%4.2f" */
          prec = width = 0;
          if (*fmt >= '0' && *fmt <= '9')
            {
              width = *fmt - '0';
              fmt++;
            }
          if (*fmt == '.')
            {
              fmt++;
              if (*fmt >= '0' && *fmt <= '9')
                {
                  prec = *fmt - '0';
                  fmt++;
                }
            }
          if (*fmt == 's') /* Format "%s" */
            {
              static const char *s;

              s = va_arg(ap, const char *);
              write(1, s, strlen(s));
            }
          else /* Format "%d" or "%f" */
            {
              static double d;
              static char n, pad;

              if (*fmt == 'd')
                {
                  d = (double)va_arg(ap, int);
                  prec = 0; /* No digits after point */
                  pad = '0';
                }
              else
                {
                  d = va_arg(ap, double);
                  /* Move digits before point */
                  for (n = prec; n != 0; n--) d *= 10.0;
                  pad = ' ';
                }
              /* Set up buffer */
              pfb.p_len = 0;
              pfb.p_str = pfb.p_buf + sizeof(pfb.p_buf);
              /* Change negative number to positive */
              n = 0;
              if (d < 0) { n = 1; d = -d; }
              modf(d + 0.5, &d); /* Round last digit */
              for (;;)
                {
                  d /= 10.0;  /* Extract next digit */
                  /* Use 10.5 instead of 10.0 to decrease error */
                  pfb_put('0' + (int)(10.5 * modf(d, &d)));
                  if (prec != 0)
                    {
                      prec--;
                      if (prec == 0) pfb_put('.');
                    }
                  else if (d < 1.0)
                    break; /* No more digits */
                }
              if (n) pfb_put('-');
              while(pfb.p_len < width) pfb_put(pad);
              write(1, pfb.p_str, pfb.p_len);
            }
          fmt++; /* Pass 's' in "%s" */
        }
    }
  va_end(ap);
}
#endif /* SMALL */
