home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / misc / volume7 / ephem / part01 next >
Encoding:
Text File  |  1989-06-03  |  40.3 KB  |  1,422 lines

  1. Newsgroups: comp.sources.misc
  2. From: allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc)
  3. Subject: v07i009: astronomical ephemeris - 1 of 3
  4. Keywords: ephermeris astro
  5. Organization: Dimensional Medicine, Inc.  Minnetonka, MN.
  6. Reply-To: ecd@ncs-med.UUCP (Elwood C. Downey)
  7.  
  8. Posting-number: Volume 7, Issue 9
  9. Submitted-by: ecd@ncs-med.UUCP (Elwood C. Downey)
  10. Archive-name: ephem/part01
  11.  
  12. [Manual uses -ms.  May I suggest that the only formatter macros you can be
  13. *sure* exist are the ones in -man?  -ms and -mm are Berkeleyisms, -me is
  14. an AT&Tism.  Maybe you should use -mn, which comes with News 2.11.  ++bsa]
  15.  
  16. Here is an ephemeris program I have written I thought I'd toss to the wind.
  17. I started it a few years ago and now it is pretty stable and I know of
  18. no bugs in it. It uses termcap on unix but all the terminal i/o is based
  19. on a very few simple functions in io.c, the intent is that it could be
  20. easily ported to DOS or other non-unix environment; even the unix version
  21. uses no other unix-ism.
  22.  
  23. I have gathered everything together into three sh archive files; this
  24. is the first. Cut this chit-chat off and run the script to create the first
  25. set of files. Do the same for the others. When it's done, you should have
  26. these files:
  27.  
  28. Makefile        # makes ephem (given lib/lib.a is done)
  29. Man.ms            # nroff -ms manual
  30. TODO            # stuff I've thought to add someday
  31. ephem.cfg        # sample configuration file
  32. borders.c
  33. circum.c
  34. circum.h
  35. io.c
  36. main.c
  37. plot.c
  38. pr.c
  39. pr0.c
  40. screen.h
  41. sel_lfd.c
  42. time.c
  43. version.c
  44. lib/Makefile        # makes the pure astronomy stuff, lib.a
  45. lib/aa_hadec.c
  46. lib/anomaly.c
  47. lib/astro.h
  48. lib/cal_mjd.c
  49. lib/eq_ecl.c 
  50. lib/moon.c 
  51. lib/moonnf.c
  52. lib/moonrs.c
  53. lib/nutation.c
  54. lib/obliq.c
  55. lib/parallax.c
  56. lib/pelement.c
  57. lib/plans.c
  58. lib/precess.c
  59. lib/refract.c
  60. lib/riset.c
  61. lib/sex_dec.c
  62. lib/sun.c
  63. lib/sunrs.c
  64. lib/utc_gst.c
  65.  
  66. (the third script makes the lib directory).
  67. When it's done, make it by making the library, then the main program::
  68.     cd lib
  69.     make
  70.     cd ..
  71.     make
  72.  
  73. then try to run it by just typing:
  74. ephem
  75.  
  76. Let me know about suggestions, bugs, problems, etc. I don't guarantee I'll
  77. maintain it particularly regularly but I'm enough of an astro nut that I will
  78. likely fool with it some more without much provoking. Enjoy!
  79.  
  80. Elwood Downey
  81. umn-cs!ncs-med!ecd
  82.  
  83. ---CUT---CUT---CUT---CUT---CUT---CUT---CUT---CUT---CUT---CUT---CUT---CUT---CUT
  84. #!/bin/sh
  85. echo extracting ephem.cfg
  86. cat > ephem.cfg << 'xXx'
  87. UT NOW
  88. LONG 93:42:8
  89. LAT 44:50:37
  90. HEIGHT 800
  91. TEMP 40
  92. PRES 29.5
  93. STPSZ RTC
  94. PROPTS TSMevajsunp
  95. EPOCH EOD
  96. SITE The Hill Observatory
  97. OBJN Orion
  98. OBJRA 6
  99. OBJDEC 0
  100. NSTEP 1
  101. xXx
  102. echo extracting Man.ms
  103. cat > Man.ms << 'xXx'
  104. .LP
  105. .ND
  106. .po .5i
  107. .nr LL 7.4i    \" line length
  108. .nr LT \n(LL    \" title length
  109. .nr FL \n(LL    \" footnote length
  110. .nr PO .5i    \" page offset
  111. .nh
  112. .nr Pd \n(PD    \" save paragraph spacing for changing .IP
  113. .na
  114. .LP
  115. .DS C
  116. Ephem
  117. V3.11
  118.  
  119. by
  120. Elwood Downey
  121. 8860 Abbywood Road
  122. Chaska, MN 55343
  123. .DE
  124. .SH
  125. Introduction
  126. .LP
  127. Ephem.exe is a program that displays observing circumstances
  128. for all the planets and any one extra object you wish to enter. Included are
  129. RA and Dec, heliocentric coordinates, azimuth and altitude, distance from
  130. sun and earth, phase, visual magnitude, solar elongation, and angular size.
  131.  
  132. It also displays local ephemeris information. Included are UTC and local
  133. date and time, local sidereal time, local sun and moon rise and set times,
  134. times of astronomical twilight, length of day and night,
  135. and a monthly calendar. 
  136.  
  137. RA/Dec calculations are geocentric and include the effects of precession,
  138. nutation and aberration.
  139. Alt/az calculations are topocentric and also include effects of refraction and
  140. parallax.
  141.  
  142. A running plot file of selected field values
  143. may be generated as the program runs.
  144. Ephem.exe includes a very crude
  145. quick-look capability to view these plot files or they may
  146. be plotted by other programs.
  147.  
  148. The program is written in C for unix or DOS. It uses only a very simple
  149. set of io routines and should be easily ported to any ASCII display.
  150. The DOS version requires the ANSI.SYS screen driver.
  151.  
  152. The planetary data and correction algorithms are taken, with permission,
  153. from "Astronomy With Your Personal Computer",
  154. by Peter Duffett-Smith, Cambridge University Press, 1985.
  155. .bp
  156. .SH
  157. Sample Display
  158. .LP
  159. Here is a typical screen from 
  160. .I ephem:
  161. .DS L
  162.                              The Hill Observatory                               
  163. Move to another field, RETURN to change this field, ? for help, or ESC to run   
  164.                                                                  May 1989       
  165. JD    2447664.08208        LST   23:24:22  TZ     5:00:00  Su Mo Tu We Th Fr Sa 
  166. UTC  13:58:12  5/17/1989   Lat   44:50:37  Long  93:42:08      1  2  3  4 NM  6 
  167. CDT   8:58:12  5/17/1989   Dawn      3:44  Dusk     22:40   7  8  9 10 11 12 13 
  168. SRis     5:44 @  61:10     StpSz RT CLOCK  NStep        1  14 15 16 17 18 19 FM 
  169. SSet    20:39 @ 299:03     Elev    800 ft  Temp      40 F  21 22 23 24 25 26 27 
  170. MRis    17:58 @ 109:36     AtmPr 29.50 in  DayLn    14:55  28 29 30 31          
  171. MSet     3:54 @ 254:42     Plot  off       NiteLn    5:04                       
  172.                                                                                 
  173. Ob R.A.    Dec    Helio  Helio  Az     Alt    Ea Dst Sn Dst Elong  Size VMag Phs
  174.    (Epoch of date)Long   Lat    Deg E  Deg Up AU(mi) AU     Deg E  ArcS      %  
  175. Su  3:37.3  19:24 236:38   0:00  94:20  32:24 1.0114               1898  -27    
  176. Mo 13:12.1 -11:48               316:42 -50:18 251450 1.0136  144.3 1772  -12  80
  177. Me  4:15.7  21:37 224:39   0:26  85:39  27:04 0.5804 0.4484    9.2 11.6  0.3   3
  178. Ve  4:23.8  21:47  83:30   0:25  84:08  25:44 1.6854 0.7200   11.1 10.0 -4.0  98
  179. Ma  6:50.0  24:18 127:03   1:48  58:11   3:21 2.2010 1.6450   44.8  4.3  1.3  95
  180. Ju  4:47.6  21:57  76:32  -0:32  80:03  21:40 6.0333 5.0725   16.6 32.6 -2.0 100
  181. Sa 18:58.1 -22:06 279:14   0:37 238:13   0:24 9.3194 10.039 -133.2 17.8  1.0 100
  182. Ur 18:20.7 -23:37 272:54  -0:15 243:35  -7:09 18.533 19.339 -141.9  3.6  5.6 100
  183. Ne 18:52.2 -21:58 280:43   0:55 239:21  -0:09 29.498 30.216 -134.5  2.1  7.9 100
  184. Pl 15:03.1  -0:16 223:51  15:46 296:22 -24:25 28.710 29.657  159.1  0.3 13.7 100
  185. Or  6:00.0   0:00                83:42  -6:18                                  
  186. .DE
  187. .SH
  188. Program Operation
  189. .LP
  190. When
  191. .I ephem
  192. is started, it first displays a disclaimer banner.
  193. Then, after any key is depressed,
  194. it reads a configuration file
  195. to set the initial values of several fields.
  196. This file, ephem.cfg by default, is described below.
  197. It then draws all fields on the screen with their initial values.
  198. The program then loops advancing time each step, by some amount you may
  199. control, and updating all fields accordingly.
  200.  
  201. There are two fields that control this looping behavior: NStep and StpSz.
  202. These control the number of steps and the amount of time
  203. to add each step, respectively. 
  204. When the number of steps, NStep, goes to 0 or any key is depressed,
  205. the looping stops and you enter 
  206. .I "command mode."
  207.  
  208. Command mode allows you to modify most of the fields.
  209. The idea is that you move to each field on the screen you wish to change
  210. and change them.
  211. When you have changed everything you want to,
  212. type ESC to update the other fields on the screen.
  213.  
  214. To change a field: move the cursor to the field;
  215. type RETURN; then
  216. type in the new value along the command line at the top according to
  217. the format indicated in the prompt. To accept the new value type RETURN,
  218. or to leave it unchanged after all type ESC.
  219. A few fields don't require you to type anything; just typing RETURN does
  220. all the work.
  221. If you can't move to it, you can't change it.
  222.  
  223. The arrow keys on most systems move the cursor around.
  224. If these do not function or function incorrectly,
  225. the h/j/k/l keys also move the cursor left/down/up/right, respectively.
  226.  
  227. When you have changed a field that would invalidate any of the other fields
  228. the message NEW CIRCUMSTANCES appears in the upper right of the screen.
  229. This will remain until you
  230. type ESC to allow at least one screen update loop to occur.
  231. If you change any time field, the StpSz value is not added to the first loop.
  232. Note also that after a series of loops, NStep is automatically reset to 1
  233. so ESC will do exactly one loop and return you to command mode.
  234.  
  235. To quit the program, type control-x from command mode.
  236. To show a simple help line, type ? any time.
  237. .bp
  238. .SH
  239. Screen Fields
  240. .LP
  241. These are the fields displayed by the program.
  242. Following each name, in parentheses, might be 
  243. "c" to mean the field may be picked to be changed or
  244. "p" to mean the field may be picked to be included in a plot (see below).
  245.  
  246. .nr PD 0
  247. .IP JD 14
  248. the current Julian date, to about 1-second accuracy.
  249. .IP LST(p)
  250. the current local sidereal time.
  251. .IP LT(c)
  252. the local timezone name.
  253. This field can be changed to any three-character mnemonic for the current time
  254. zone name.
  255. .IP UTC(cp)
  256. universally coordinated time. set to NOW to set from computer clock.
  257. .IP TZ(cp)
  258. hours local time is behind utc, ie, >0 west, <0 east of Greenwich.
  259. .IP Lat(cp)
  260. location latitude, positive degrees north of equator.
  261. .IP Long(cp)
  262. location longitude, positive degrees west of greenwich meridian.
  263. .IP Temp(cp)
  264. local surface air temperature, in degrees F.
  265. .IP AtmPr(cp)
  266. local surface air pressure, in inches of mercury.
  267. .IP NStep(c)
  268. The number of times the display with be updated (time advanced by StpSz each
  269. step) before entering command mode.
  270. .IP StpSz(c)
  271. the amount of time UTC (and its derivatives) is incremented each loop.
  272. set this to RTC to use real-time based on the computer clock.
  273. you may also set it in terms of days by appending a D (or d)
  274. after the number when you set it.
  275. .IP Elev(cp)
  276. local elevation of the ground above sea level, in feet.
  277. .IP Dusk(cp)
  278. local time when the sun is about 15 degrees below the horizon after sunset.
  279. .IP SRis(cp)
  280. local time when the sun upper limb appears, ie, sunrise.
  281. .IP MRis(cp)
  282. Local time when the moon upper limb appears, ie, moonrise.
  283. .IP Dawn(cp)
  284. local time when the sun is about 18 degrees below the horizon before sunrise
  285. .IP SSet(cp)
  286. local time when the sun upper limb disappears, ie, sunset.
  287. .IP MSet(cp)
  288. local time when the moon upper limb disappears, ie, moonset.
  289. .IP DayLn(cp)
  290. length of time sun is above horizon, ie, SSet - SRis.
  291. .IP NiteLn(cp)
  292. length of astronical night, ie, Dawn - Dusk.
  293. .IP Plot(c)
  294. controls plotting; see separate discussion, below.
  295. .nr PD \(Pd
  296.  
  297. In the upper right of the screen is a calendar for the current local month.
  298. Dates of new and full moons are marked NM and FM, respectively.
  299.  
  300. .LP
  301. Some things may be turned off to reduce compute times.
  302. Each planet may be turned on and off 
  303. by selecting the planet name field.
  304. The calculation of dawn/dusk, sunrise/set, and moonrise/set may each be
  305. turned on and off by selecting their fields (note
  306. that even when they are turned
  307. on the software only recalculates them when the local date changes.)
  308. .bp
  309. .LP
  310. The planets are displayed in a table in the bottom portion of the screen.
  311. There is one row per planet, and several columns, described next.
  312. .LP
  313. One object may also be added to the display by putting its name and location
  314. in the bottom row of the screen. This is done by moving the cursor to
  315. the bottom row and selecting the field under the Ob, R.A., and Dec columns.
  316.  
  317. .nr PD 0
  318. .IP Ob 14
  319. name of object.
  320. .IP R.A.(p)
  321. right ascension of object, precessed to given epoch.
  322. .IP Dec(p)
  323. declination of object, precessed to given epoch.
  324. .IP Helio Long(p)
  325. heliocentric longitude. the earth's is displayed on the Sun's line.
  326. .IP Helio Lat(p)
  327. heliocentric latitude.
  328. .IP Az(p)
  329. degrees eastward of true north for object.
  330. .IP Alt(p)
  331. degrees up from a horizontal plane Elev feet above sea level.
  332. .IP "Ea Dst(p)"
  333. distance from earth center to object center, in AU, except distance
  334. to moon is in miles.
  335. .IP "Sn Dst(p)"
  336. distance from sun center to object center, in AU.
  337. .IP Elong(p)
  338. spherical angular separation between sun and  object. note this
  339. is not just difference in ecliptic longitude. the sign, however, is
  340. simply sign(obj_long - sun_long), ie, degrees east. thus, a positive
  341. elongation means the object rises after the sun.
  342. .IP Size(p)
  343. angular size of object, in arc seconds.
  344. .IP VMag(p)
  345. visual magnitude of object.
  346. .IP Phs(p)
  347. percent of visible surface in sunlight, ie, the phase. note the
  348. moon phase is calculated simplistically as just abs(elongation)/180*100
  349. which can be a few degrees off... this means that because of how
  350. elongation is defined it doesn't say 0 during new moon (or 100 during full)
  351. except during close eclipses (maybe that's a "feature"?).
  352. .nr PD \n(Pd
  353.  
  354. The precession epoch is displayed beneath the RA/DEC column headings.
  355. .bp
  356. .SH
  357. Date and Time Formats.
  358. .LP
  359. Times are displayed and entered in h:m:s format.
  360. Any of the h, m, and s components that are not specified are left unchanged
  361. from their current value.
  362. For example, 0:5:0 set hours to 0, minutes to 5, seconds to 0, whereas :5
  363. sets minutes to 5 but leaves hours and seconds unchanged.
  364. A negative time is indicated by
  365. a minus sign (-) anywhere before the first digit.
  366.  
  367. Dates are displayed and entered in American m:d:y format.
  368. As with time,
  369. components omitted remain the current value.
  370. For example, if the current date is 10/20/1988 and you type 20/20 the new
  371. date will become 20/20/1988. Note you must type the full year since the
  372. program is accurate over several centuries either side of 1900.
  373. .SH
  374. Configuration File
  375. .LP
  376. The ephem.cfg configuration file allows you to set the initial values of
  377. many of the screen fields. You can still change any field while the program
  378. is running too; this file just sets the initial conditions.
  379.  
  380. You can have several different configuration files if you wish. By
  381. default, 
  382. .I ephem
  383. looks for one named ephem.cfg. You can tell it to use
  384. an alternate file by using the -c switch as follows:
  385. .DS L
  386.     ephem -c <filespec>
  387. .DE
  388.  
  389. The format of the file uses the form KEYWORD=VALUE, where the possible
  390. KEYWORDS and the types of VALUES for each are described below. Any KEYWORDS
  391. not in the file will take on some sort of default.
  392.  
  393. Note:
  394. because of the way unspecified time and date components are left unchanged
  395. (see section on Date and Time Formats) always specify the complete time and
  396. date for all entries in the configuration file. For example, to initialize
  397. the longitude to zero degrees, say 0:0:0, not just 0.
  398.  
  399. .nr PD 0
  400. .IP UD 10
  401. initial UTC date, such as 10/20/1988 or NOW to use the computer clock.
  402. .IP TZONE
  403. hours the local time is behind utc, such as 5:0:0.
  404. you need not set this if you use NOW for UT or UD.
  405. .IP TZNAME
  406. name of the local time zone, such as CDT. 3 chars max.
  407. you need not set this if you use NOW for UT or UD.
  408. .IP LONG
  409. longitude, in degrees west of greenwich, in the form d:m:s.
  410. .IP LAT
  411. latitude, in degrees north of the equator, in the form d:m:s.
  412. .IP HEIGHT
  413. height above sea level, in feet, such as 800
  414. .IP TEMP
  415. air temperature, in degrees F, such as 50
  416. .IP PRES   
  417. air pressure, in inches of Mercury, such as 29
  418. .IP STPSZ
  419. the time increment between screen updates, such as "1" to give one
  420. hour updates. this can be a specific amount or RTC to use the system
  421. clock as a real-time source. You may also specify a time in days, by
  422. appending a D (or d) after the number.
  423. .IP PROPTS 
  424. this selects what you want included in the display. since IBM-PC math
  425. is not very fast, you can reduce the time to update the screen
  426. by only printing those fields of interest. the VALUE is a collection
  427. of letters to turn on each item from the following set:
  428. .DS L
  429.     T    twilight (dawn-dusk)
  430.     S    sun rise/set and circumstance for the sun
  431.     M    moon rise/set and circumstance for the moon
  432.     e    circumstances for mercury
  433.     v    circumstances for venus
  434.     a    circumstances for mars
  435.     j    circumstances for jupiter
  436.     s    circumstances for saturn
  437.     u    circumstances for uranus
  438.     n    circumstances for neptune
  439.     p    circumstances for pluto
  440. .DE
  441. For example, to just display sun rise/set and track the sun and
  442. saturn, say PROPTS Ss
  443. .IP NSTEP  
  444. number of times program will loop before entering command mode.
  445. see the discussion under Program Operation.
  446. .IP EPOCH
  447. this sets the desired ra/dec precession epoch. you can put any date
  448. here or EOD to use the current instant ("Epoch of Date").
  449. .IP SITE
  450. the name of the observing site. it places the characters found here
  451. across the top of the screen as a title.
  452. .IP OBJN
  453. name of the extra object to track.
  454. .IP OBJRA
  455. right ascension of the extra object to track.
  456. .IP OBJDEC
  457. declination of the extra object to track.
  458. .nr PD \n(Pd
  459. .bp
  460. .LP
  461. Example ephem.cfg files:
  462.  
  463. .DS L
  464. Create an essentially free-running real-time update:
  465.  
  466. UT NOW
  467. LONG 90:10:8
  468. LAT 40:50:20
  469. HEIGHT 800
  470. TEMP 50
  471. PRES 29
  472. STPSZ RTC
  473. PROPTS TSMevajsunp
  474. NSTEP 10000000
  475. EPOCH EOD
  476. SITE The Observatory
  477. .DE
  478.  
  479. .DS L
  480. Initialize things to investigate the 1991 Hawaiian solar eclipse:
  481.  
  482. UD 7/11/1991
  483. UT 19:10:0
  484. LAT 20:30:0
  485. LONG 157:0:0
  486. TZONE 10
  487. TZNAME HST
  488. EPOCH 2000
  489. PRES 30
  490. HEIGHT 0
  491. TEMP 80
  492. SETPSZ :10
  493. NSTEP 1
  494. PROPTS SM
  495. SITE 1991 Hawaii Eclipse
  496. .DE
  497. .bp
  498. .SH Plotting
  499. .LP
  500. Each time a field is drawn on the screen its full-precision
  501. value may be written to a file.
  502. Each line in the file consists of a tag character followed by two or three
  503. floating point variables, all separated by commas. If there are two
  504. values, they should be interpreted to be x and y (or perhaps r and theta).
  505. If there is a third, it is a z or trace value.
  506. .LP
  507. The "Plot" field controls plotting.
  508. Whether plotting is currently active is indicated by "on" or "off" immediately
  509. to its right.
  510. .LP
  511. To initiate a plot file, pick the "off" field. You will be asked for the
  512. name of the file to use and, if it already exists, whether to overwrite it or
  513. append to it. Once you have chosen a file, plotting is on and the field changes
  514. to "on".
  515. .LP
  516. You should then define which fields should be plotted. Select the "Plot"
  517. field. You will be asked
  518. for a tag character, then asked
  519. to move the cursor to the field you want to use as the x coordinate (abscissa),
  520. then asked to choose the y coordinate (ordinate), then asked to choose an
  521. optional z trace variable.
  522. You may choose up to four of these sets for any given plot run. Type ESC to
  523. quick making choices and begin plotting. The values are written to the plot
  524. file each time they are updated on the screen until you select "on" to turn
  525. plotting back off.
  526. .LP
  527. You may use 
  528. .I ephem
  529. to make a crude plot of the plot files. When plotting is
  530. off, select the "Plot" field and give a filename. The entries will be
  531. drawn with their tag characters; the plot remains on the screen until you 
  532. type any character.
  533. .bp
  534. .SH
  535. Implementation Notes
  536. .LP
  537. All rise/set times are for the current local date.
  538. However, if the event occurred just before midnight this morning
  539. the time reported might be for the previous day, and similarly after tonights
  540. midnight. If in doubt, set the time and check the altitude.
  541.  
  542. The calendar is for current local month.
  543.  
  544. The program uses a horizontal plane tangent to the earth as the
  545. horizon for all altitude calculations, rise/set events, etc.
  546. This is
  547. .I not
  548. the same as the angle up from the local horizon unless the observer is
  549. directly on the ground due to earth's curvature.
  550. The effect can be found from:
  551. .DS L
  552.     sin(a)**2 = (h**2 + 2Rh) / (R+h)**2
  553.     where:
  554.     R = radius of earth
  555.     h = height above ground (same units as R)
  556.     a = increase in altitude
  557. .DE
  558. For example, the effect is more than two arc minutes at a height of 5 feet.
  559.  
  560. visual magnitudes are not very accurate at all... haven't bother to fix.
  561.  
  562. internally, the program is good to a few tens of arc seconds on the planets;
  563. displaying to nearest arc minute should be quite reliable.
  564. a "negative 0" is displayed when a value is negative but less than half the 
  565. display precision.
  566.  
  567. The sun-moon distance is the solution for the third side of a planar triangle
  568. whose two other sides are the earth-moon distance and earth-sun
  569. distance separated by the angle of elongation.
  570.  
  571. Sun 
  572. rise and set times and azimuths could be found from an iteration directly on
  573. altitude. However, the "standard" algorithm is based on a fixed, average
  574. refraction correction at sea level (elevation makes a slight effect on moon
  575. times). This matches published values pretty well.
  576. The "adaptive" algorithm takes into
  577. account the air pressure and temperture and sun diameter but I have
  578. no independent means to check (eg, an ocean).
  579. Anyway, I figure it isn't worth too much effort.
  580. .bp
  581. .SH
  582. DOS Installation Procedure
  583. .LP
  584. Summary:
  585.  
  586. You must be running DOS V2.0 or later.
  587. A 8087 floating point chip will be used if present.
  588.  
  589. The distribution floppy contains two files, ephem.exe and ephem.cfg.
  590. Ephem.exe is the executable program; ephem.cfg is a sample configuration
  591. file. To run the program, make working copies of these two files
  592. in a directory and run "ephem" from that directory. The program uses the
  593. ANSI.SYS terminal driver for screen control. It also uses an
  594. environment variable, TZ, to establish the local timezone.
  595.  
  596. Details:
  597. .DS L
  598. 1) The ANSI.SYS screen driver is required for this program. Edit the
  599.    CONFIG.SYS file, if necessary, so it contains the following line:
  600.      ANSI.SYS
  601.  
  602.    If it wasn't already there and you had to add it, note it will not
  603.    take effect until you reboot DOS.
  604.  
  605. 2) Set a DOS environment variable, TZ, in the following form:
  606.      set TZ=SSSnDDD
  607.  
  608.    "SSS" is the 3-letter abbreviation for the local standard timezone;
  609.    "n"   is a number between -23 to 24 indicating the number of hours
  610.      that are subtracted from GMT to obtain local standard time;
  611.    "DDD" is an optional 3-letter abbreviation for the local daylight savings
  612.      time zone name. Leave it off if you do not have savings time in your
  613.      area. If the changeover dates differ from the internal algorithm,
  614.      just use SSS and n directly.
  615.  
  616.  
  617.     For example, in the midwestern United States with savings times:
  618.      set TZ=CST6CDT
  619.  
  620.     You can put this in your AUTOEXEC.BAT file so it gets set each time
  621.     you boot DOS.
  622.  
  623. 2) place the distribution floppy into drive a:. 
  624.  
  625. 3) copy the ephem.* files to a working diskette:
  626.     copy ephem.* b:*.*/v
  627. or hard disk:
  628.     copy ephem.* c:*.*/v
  629.  
  630. 4) run using the sample configuration file by just running 
  631.     ephem
  632.  
  633. To run with a different configuration file, use the -c switch:
  634.     ephem -c <filespec>
  635. .DE
  636. xXx
  637. echo extracting TODO
  638. cat > TODO << 'xXx'
  639. allow for plotting backwards: times down, ra left
  640.  
  641. add facility for finding max alt on a given day. useful for plotting
  642. planet sky positions over many days.
  643.  
  644. rise, set times for each planet?
  645.  
  646. new scheme for showing more info/planet than can fit on one line.
  647. for example, make a new pick that allows selection of what you DO want
  648. displayed, up to the maximum allowable columns. add all rise/set, times,
  649. the new max alt, etc
  650.  
  651. a real-time plot mode. select fields to plot and update.
  652. could watch planets revolve around sun, or watch them go across the sky.
  653. xXx
  654. echo extracting Makefile
  655. cat > Makefile << 'xXx'
  656. CLNFLAGS=$(CLNF)
  657. LNFLAGS=$(CLNFLAGS) $(LNF)
  658. CFLAGS=$(CLNFLAGS) $(CF) -Ilib
  659. LIBRARIES=lib/lib.a /usr/lib/libtermcap.a
  660. LINTFLAGS=$(CFLAGS) $(LINTF)
  661. LINTLIBS=
  662.  
  663. EPHEM=    borders.o \
  664.     circum.o \
  665.     io.o \
  666.     main.o \
  667.     plot.o \
  668.     pr.o \
  669.     pr0.o \
  670.     sel_fld.o \
  671.     time.o \
  672.     version.o \
  673.     $(LIBRARIES)
  674. ephem:    $(EPHEM)
  675.     $(CC) -o $@ $(LNFLAGS) $(EPHEM) $(LNTAIL)
  676. xXx
  677. echo extracting borders.c
  678. cat > borders.c << 'xXx'
  679. #include "screen.h"
  680.  
  681. borders()
  682. {
  683. /*
  684.     register i;
  685.  
  686.     for (i = 1; i <= 80; i++)
  687.         pr_char (R_PLANTAB-1, i, '-');
  688.     for (i = R_LST; i < R_PLANTAB-1; i++)
  689.         pr_char (i, C_LST-1, '|');
  690.     for (i = R_TZONE; i < R_PLANTAB-1; i++)
  691.         pr_char (i, C_TZONE-1, '|');
  692.     for (i = R_CAL+1; i < R_PLANTAB-1; i++)
  693.         pr_char (i, C_CAL-1, '|');
  694. */
  695. }
  696. xXx
  697. echo extracting circum.c
  698. cat > circum.c << 'xXx'
  699. #include <stdio.h>
  700. #include <math.h>
  701. #include "astro.h"
  702. #include "circum.h"
  703.  
  704. /* shorthands into np */
  705. #define mjd    np->n_mjd
  706. #define lat    np->n_lat
  707. #define lng    np->n_lng
  708. #define tz    np->n_tz
  709. #define temp    np->n_temp
  710. #define pressure    np->n_pressure
  711. #define height    np->n_height
  712.  
  713. /* find sun's circumstances now */
  714. sun_cir (np, sp)
  715. Now *np;
  716. Sky *sp;
  717. {
  718.     static Sky last_sky;
  719.     static Now last_now;
  720.     float lst, alt, az;
  721.  
  722.     if (same_cir (np, &last_now) && about_now (np, &last_now, 7e-4))
  723.         *sp = last_sky;
  724.     else {
  725.         float lsn, rsn;
  726.         float deps, dpsi;
  727.  
  728.         last_now = *np;
  729.         sun ((float)mjd,&lsn,&rsn); /* sun's true ecliptic long and dist */
  730.         nutation ((float)mjd,&deps,&dpsi);    /* correct for nutation */
  731.         lsn += dpsi-degrad(20.4/3600);    /* and 20.4" aberration */
  732.  
  733.         sp->s_edist = rsn;
  734.         sp->s_sdist = 0.0;
  735.         sp->s_size = raddeg(4.65242e-3/rsn)*3600*2;
  736.         sp->s_mag = -26.8;
  737.         sp->s_hlong = lsn-PI;    /* geo- to helio- centric */
  738.         range (&sp->s_hlong, 2*PI);
  739.         sp->s_hlat = 0.0;
  740.  
  741.         ecl_eq ((float)mjd, 0.0, lsn, &sp->s_ra, &sp->s_dec);
  742.     }
  743.  
  744.     now_lst (np, &lst);
  745.     hadec_aa (lat, hrrad(lst) - sp->s_ra, sp->s_dec, &alt, &az);
  746.     refract (pressure, temp, alt, &alt);
  747.     sp->s_alt = alt;
  748.     sp->s_az = az;
  749.     last_sky = *sp;
  750. }
  751.  
  752. /* find moon's circumstances now */
  753. moon_cir (np, sp)
  754. Now *np;
  755. Sky *sp;
  756. {
  757.     static Sky last_sky;
  758.     static Now last_now;
  759.     static float ehp;
  760.     float lst, alt, az;
  761.     float ha, dec;
  762.  
  763.     if (same_cir (np, &last_now) && about_now (np, &last_now, 2e-4))
  764.         *sp = last_sky;
  765.     else {
  766.         float lam, bet;
  767.         float deps, dpsi;
  768.         float lsn, rsn;    /* sun long in rads, earth-sun dist in au */
  769.         float edistau;    /* earth-moon dist, in au */
  770.         float el;        /* elongation, rads east */
  771.  
  772.         last_now = *np;
  773.         moon ((float)mjd,&lam,&bet,&ehp);    /* moon's true ecliptic loc */
  774.         nutation ((float)mjd,&deps,&dpsi);    /* correct for nutation */
  775.         lam += dpsi;
  776.         range (&lam, 2*PI);
  777.  
  778.         sp->s_edist = 6378.14/sin(ehp);    /* earth-moon dist, want km */
  779.         sp->s_size = 3600*31.22512*sin(ehp);/* moon angular dia, seconds */
  780.  
  781.         ecl_eq ((float)mjd, bet, lam, &sp->s_ra, &sp->s_dec);
  782.  
  783.         sun ((float)mjd, &lsn, &rsn);
  784.         range (&lsn, 2*PI);
  785.         elongation (lam, bet, lsn, &el);
  786.  
  787.         /* solve triangle of earth, sun, and elongation for moon-sun dist */
  788.         edistau = sp->s_edist/1.495979e8; /* km -> au */
  789.         sp->s_sdist =
  790.         sqrt (edistau*edistau + rsn*rsn - 2.0*edistau*rsn*cos(el));
  791.  
  792.         /* TODO: improve mag; this is based on a flat moon model. */
  793.         sp->s_mag = -12 + 2.5*(log10(PI) - log10(PI/2*(1+1.e-6-cos(el))));
  794.  
  795.         sp->s_elong = raddeg(el);    /* want degrees */
  796.         sp->s_phase = fabs(el)/PI*100.0;    /* want non-negative % */
  797.         sp->s_hlong = sp->s_hlat = 0.0;
  798.     }
  799.  
  800.     /* show topocentric alt/az by correcting ra/dec for parallax 
  801.      * as well as refraction.
  802.      */
  803.     now_lst (np, &lst);
  804.     ha = hrrad(lst) - sp->s_ra;
  805.     ta_par (ha, sp->s_dec, lat, height, ehp, &ha, &dec);
  806.     hadec_aa (lat, ha, dec, &alt, &az);
  807.     refract (pressure, temp, alt, &alt);
  808.     sp->s_alt = alt;
  809.     sp->s_az = az;
  810.     last_sky = *sp;
  811. }
  812.  
  813. /* find planet p's circumstances now */
  814. planet_cir (p, np, sp)
  815. int p;
  816. Now *np;
  817. Sky *sp;
  818. {
  819.     typedef struct {
  820.         float l_every;    /* recalc l_sky every these days */
  821.         Now l_now;        /* when l_sky was found */
  822.         Sky l_sky;
  823.     } Last;
  824.     /* set to number of days planet takes to move about 1 arcsec */
  825.     static Last last[8] =
  826.         {{2e-4},{4e-4},{1e-3},{.006},{.02},{.06},{.1},{.2}};
  827.     float lst, alt, az;
  828.     register Last *lp = last + p;
  829.  
  830.     /* if less than l_every days from last time for this planet
  831.      * just redo alt/az.
  832.      */
  833.     if (same_cir(np, &lp->l_now) && about_now (np, &lp->l_now, lp->l_every))
  834.         *sp = lp->l_sky;
  835.     else {
  836.         float lpd0, psi0; /* heliocentric ecliptic longitude and latitude */
  837.         float rp0;    /* dist from sun */
  838.         float rho0;    /* dist from earth */
  839.         float lam, bet;    /* geocentric ecliptic long and lat */
  840.         float dia, mag;    /* angular diameter at 1 AU and magnitude */
  841.         float lsn, rsn;    /* true geoc lng of sun, dist from sn to earth*/
  842.         float deps, dpsi;
  843.         float a, ca, sa;
  844.         float el;    /* elongation */
  845.         float f;    /* phase from earth */
  846.  
  847.         lp->l_now = *np;
  848.         plans ((float)mjd,p,&lpd0,&psi0,&rp0,&rho0,&lam,&bet,&dia,&mag);
  849.         nutation ((float)mjd, &deps, &dpsi); /* correct for nutation */
  850.         lam += dpsi;
  851.         sun ((float)mjd, &lsn, &rsn);
  852.         /* correct for 20.4" aberration */
  853.         a = lsn-lam;
  854.         ca = cos(a);
  855.         sa = sin(a);
  856.         lam -= degrad(20.4/3600)*ca/cos(bet);
  857.         bet -= degrad(20.4/3600)*sa*sin(bet);
  858.  
  859.         ecl_eq ((float)mjd, bet, lam, &sp->s_ra, &sp->s_dec);
  860.         sp->s_edist = rho0;
  861.         sp->s_sdist = rp0;
  862.         elongation (lam, bet, lsn, &el);
  863.         el = raddeg(el);
  864.         sp->s_elong = el;
  865.         sp->s_size = dia/rho0;
  866.         f = 0.5*(1+cos(lam-lpd0));
  867.         sp->s_phase = f*100.0; /* percent */
  868.         sp->s_mag = 5.0*log(rp0*rho0/sqrt(f))/log(10.0) + mag;
  869.         sp->s_hlong = lpd0;
  870.         sp->s_hlat = psi0;
  871.     }
  872.  
  873.     /* alt, az; correct for refraction, in place */
  874.     now_lst (np, &lst);
  875.     hadec_aa (lat, hrrad(lst) - sp->s_ra, sp->s_dec, &alt, &az);
  876.     refract (pressure, temp, alt, &alt);
  877.     sp->s_alt = alt;
  878.     sp->s_az = az;
  879.     lp->l_sky = *sp;
  880. }
  881.  
  882. /* find s_ra/dec/alt/az @ EOD for object at given loc */
  883. obj_cir (ra, dec, e, np, sp)
  884. float ra, dec, e;    /* objects location and epoch of coords */
  885. Now *np;
  886. Sky *sp;
  887. {
  888.     float lst, alt, az;
  889.  
  890.     /* always want EOD ra/dec in Sky */
  891.     sp->s_ra = ra;
  892.     sp->s_dec = dec;
  893.     if (e != mjd)
  894.         precess (e, (float)mjd, &sp->s_ra, &sp->s_dec);
  895.  
  896.     /* find alt/az based on EOD */
  897.     now_lst (np, &lst);
  898.     hadec_aa (lat, hrrad(lst) - sp->s_ra, sp->s_dec, &alt, &az);
  899.     refract (pressure, temp, alt, &alt);
  900.     sp->s_alt = alt;
  901.     sp->s_az = az;
  902. }
  903.  
  904. /* find times when sun is 18 degrees below horizon */
  905. twilight_cir (np, dawn, dusk, status)
  906. Now *np;
  907. float *dawn, *dusk;
  908. int *status;
  909. {
  910.     static Now last_now;
  911.     static float last_dawn, last_dusk;
  912.     static int last_status;
  913.  
  914.     if (same_cir (np, &last_now) && same_lday (np, &last_now)) {
  915.         *dawn = last_dawn;
  916.         *dusk = last_dusk;
  917.         *status = last_status;
  918.     } else {
  919.         float tmp;
  920.         sunrs ((float)(mjd-tz/24.0), lat, lng, degrad(18.), dawn, dusk,
  921.                                 &tmp, &tmp, status);
  922.         last_dawn = *dawn;
  923.         last_dusk = *dusk;
  924.         last_status = *status;
  925.         last_now = *np;
  926.     }
  927. }
  928.  
  929. sunrs_cir (np, dis, utcr, utcs, azr, azs, status)
  930. Now *np;
  931. float dis;
  932. float *utcr, *utcs, *azr, *azs;
  933. int *status;
  934. {
  935.     static Now last_now;
  936.     static float last_r, last_s, last_azr, last_azs, last_dis;
  937.     static int last_status;
  938.  
  939.     if (same_cir (np, &last_now) && same_lday (np, &last_now)
  940.         && last_dis == dis) {
  941.         *utcr = last_r;
  942.         *utcs = last_s;
  943.         *azr = last_azr;
  944.         *azs = last_azs;
  945.         *status = last_status;
  946.     } else {
  947.         last_dis = dis; /* save before we modify it in place if ADPREF */
  948.         if (dis == ADPREF) {
  949.         /* use the real sun diameter and current refraction conditions.
  950.          * unrefract the sun upper limb, then subtract sun semi-diam.
  951.          */
  952.         Sky sk;
  953.         unrefract (pressure, temp, 0.0, &dis);
  954.         sun_cir (np, &sk);
  955.         dis -= degrad(sk.s_size/3600./2.0);
  956.         dis = -dis;
  957.         }
  958.         sunrs ((float)(mjd-tz/24.0), lat, lng, dis, utcr, utcs, azr, azs,
  959.                                     status);
  960.         last_r = *utcr;
  961.         last_s = *utcs;
  962.         last_azr = *azr;
  963.         last_azs = *azs;
  964.         last_status = *status;
  965.         last_now = *np;
  966.     }
  967. }
  968.  
  969. moonrs_cir (np, utcr, utcs, azr, azs, status)
  970. Now *np;
  971. float *utcr, *utcs, *azr, *azs;
  972. int *status;
  973. {
  974.     static Now last_now;
  975.     static float last_r, last_s, last_azr, last_azs;
  976.     static int last_status;
  977.  
  978.     if (same_cir (np, &last_now) && same_lday (np, &last_now)) {
  979.         *utcr = last_r;
  980.         *utcs = last_s;
  981.         *azr = last_azr;
  982.         *azs = last_azs;
  983.         *status = last_status;
  984.     } else {
  985.         moonrs ((float)(mjd-tz/24.0), lat, lng, utcr, utcs, azr, azs,
  986.                                     status);
  987.         last_r = *utcr;
  988.         last_s = *utcs;
  989.         last_azr = *azr;
  990.         last_azs = *azs;
  991.         last_status = *status;
  992.         last_now = *np;
  993.     }
  994. }
  995.  
  996. /* given geocentric ecliptic longitude and latitude, lam and bet, of some object
  997.  * and the longitude of the sun, lsn, find the elongation, el. this is the
  998.  * actual angular separation of the object from the sun, not just the difference
  999.  * in the longitude. the sign, however, IS set simply as a test on longitude
  1000.  * such that el will be >0 for an evening object <0 for a morning object.
  1001.  * to understand the test for el sign, draw a graph with lam going from 0-2*PI
  1002.  *   down the vertical axis, lsn going from 0-2*PI across the hor axis. then
  1003.  *   define the diagonal regions bounded by the lines lam=lsn+PI, lam=lsn and
  1004.  *   lam=lsn-PI. the "morning" regions are any values to the lower left of the
  1005.  *   first line and bounded within the second pair of lines.
  1006.  * all angles in radians.
  1007.  */
  1008. static
  1009. elongation (lam, bet, lsn, el)
  1010. float lam, bet, lsn;
  1011. float *el;
  1012. {
  1013.     *el = acos(cos(bet)*cos(lam-lsn));
  1014.     if (lam>lsn+PI || lam>lsn-PI && lam<lsn) *el = - *el;
  1015. }
  1016.  
  1017. /* return whether the two Nows are for the same observing circumstances. */
  1018. static
  1019. same_cir (n1, n2)
  1020. register Now *n1, *n2;
  1021. {
  1022.     return (n1->n_lat == n2->n_lat
  1023.         && n1->n_lng == n2->n_lng
  1024.         && n1->n_temp == n2->n_temp
  1025.         && n1->n_pressure == n2->n_pressure
  1026.         && n1->n_height == n2->n_height);
  1027. }
  1028.  
  1029. /* return whether the two Nows are for the same LOCAL day */
  1030. static
  1031. same_lday (n1, n2)
  1032. Now *n1, *n2;
  1033. {
  1034.     return (mjd_day(n1->n_mjd - n1->n_tz/24.0) ==
  1035.         mjd_day(n2->n_mjd - n2->n_tz/24.0)); 
  1036. }
  1037.  
  1038. /* return whether the mjd of the two Nows are within dt */
  1039. static
  1040. about_now (n1, n2, dt)
  1041. Now *n1, *n2;
  1042. float dt;
  1043. {
  1044.     return (fabs (n1->n_mjd - n2->n_mjd) < dt);
  1045. }
  1046.  
  1047. now_lst (np, lst)
  1048. Now *np;
  1049. float *lst;
  1050. {
  1051.     utc_gst ((float)mjd_day(mjd), (float)mjd_hr(mjd), lst);
  1052.     *lst += radhr(lng);
  1053.     range (lst, 24.0);
  1054. }
  1055.  
  1056. /* round a time in days, *t, to the nearest second, IN PLACE. */
  1057. rnd_second (t)
  1058. double *t;
  1059. {
  1060.     *t = floor(*t*SPD+0.5)/SPD;
  1061. }
  1062.     
  1063. double mjd_day(jd)
  1064. double jd;
  1065. {
  1066.     return (floor(jd-0.5)+0.5);
  1067. }
  1068.  
  1069. double mjd_hr(jd)
  1070. double jd;
  1071. {
  1072.     return ((jd-mjd_day(jd))*24.0);
  1073. }
  1074. xXx
  1075. echo extracting circum.h
  1076. cat > circum.h << 'xXx'
  1077. #define    SPD    (24.0*3600.0)    /* seconds per day */
  1078. #define    EOD    (-9876)        /* special epoch flag: use epoch of date */
  1079. #define    RTC    (-1234)        /* special tminc flag: use rt clock */
  1080. #define    ADPREF    (-100)        /* special sunrs dis flag: use pres/temp */
  1081.  
  1082. /* info about our local observing circumstances */
  1083. typedef struct {
  1084.     double n_mjd;    /* modified Julian date, ie, days since
  1085.              * Jan 0.5 1900 (== 12 noon, Dec 30, 1899), utc.
  1086.              * enough precision to get well better than 1 second.
  1087.              */
  1088.     float n_lat;    /* latitude, >0 north, rads */
  1089.     float n_lng;    /* longitude, >0 east, rads */
  1090.     float n_tz;    /* time zone, hrs behind UTC */
  1091.     float n_temp;    /* atmospheric temp, degrees C */
  1092.     float n_pressure; /* atmospheric pressure, mBar */
  1093.     float n_height;    /* height above sea level, earth radii */
  1094.     char n_tznm[4];    /* time zone name; 3 chars or less, always 0 at end */
  1095. } Now;
  1096. extern double    mjd_day(), mjd_hr();
  1097.  
  1098. /* info about where and how we see something in the sky */
  1099. typedef struct {
  1100.     float s_ra;    /* ra, rads (equinox of date) */
  1101.     float s_dec;    /* dec, rads (equinox of date) */
  1102.     float s_az;    /* azimuth, >0 e of n, rads */
  1103.     float s_alt;    /* altitude above topocentric horizon, rads */
  1104.     float s_sdist;    /* dist from object to sun, au */
  1105.     float s_edist;    /* dist from object to earth, au */
  1106.     float s_elong;    /* angular sep between object and sun, >0 if east */
  1107.     float s_hlong;    /* heliocentric longitude, rads */
  1108.     float s_hlat;    /* heliocentric latitude, rads */
  1109.     float s_size;    /* angular size, arc secs */
  1110.     float s_phase;    /* phase, % */
  1111.     float s_mag;    /* visual magnitude */
  1112. } Sky;
  1113. xXx
  1114. echo extracting io.c
  1115. cat > io.c << 'xXx'
  1116. /* this file (in principle) contains all the device-dependent code for
  1117.  * handling screen movement and reading the keyboard. public routines are:
  1118.  *   c_pos(r,c), c_erase(), c_eol();
  1119.  *   chk_char(), read_char(), read_line (buf, max); and
  1120.  *   byetty().
  1121.  * N.B. we assume output may be performed by printf() and putchar(). output
  1122.  *   buffering has been disabled elsewhere as setbuf((char *)0).
  1123.  * #define UNIX or LATTICE_C to give two popular versions.
  1124.  * UNIX uses termcap; LATTICE_C uses ANSI and the IBM-PC keyboard codes.
  1125.  */
  1126.  
  1127. #define    UNIX
  1128. /* #define LATTICE_C */
  1129.  
  1130. #include <stdio.h>
  1131.  
  1132. #define    CNTRL(c)    ((c)&037)
  1133. #define    ESC        CNTRL('[')
  1134.  
  1135. #ifdef UNIX
  1136. #include <sgtty.h>
  1137. #include <signal.h>
  1138.  
  1139. extern char *tgoto();
  1140. static char *cm, *ce, *cl, *kl, *kr, *ku, *kd; /* curses sequences */
  1141. static int tloaded;
  1142. static int ttysetup;
  1143. static struct sgttyb orig_sgtty;
  1144.  
  1145. /* move cursor to row, col, 1-based.
  1146.  * we assume this also moves a visible cursor to this location.
  1147.  */
  1148. c_pos (r, c)
  1149. int r, c;
  1150. {
  1151.     if (!tloaded) tload();
  1152.     fputs (tgoto (cm, c-1, r-1), stdout);
  1153. }
  1154.  
  1155. /* erase entire screen. */
  1156. c_erase()
  1157. {
  1158.     if (!tloaded) tload();
  1159.     fputs (cl, stdout);
  1160. }
  1161.  
  1162. /* erase to end of line */
  1163. c_eol()
  1164. {
  1165.     if (!tloaded) tload();
  1166.     fputs (ce, stdout);
  1167. }
  1168.  
  1169. /* return 0 if there is a char that may be read without blocking, else -1 */
  1170. chk_char()
  1171. {
  1172.     long n = 0;
  1173.     if (!ttysetup) setuptty();
  1174.     ioctl (0, FIONREAD, &n);
  1175.     return (n > 0 ? 0 : -1);
  1176. }
  1177.  
  1178. /* read the next char, blocking if necessary, and return it. don't echo.
  1179.  * map the arrow keys if we can too into hjkl
  1180.  */
  1181. read_char()
  1182. {
  1183.     char c;
  1184.     if (!ttysetup) setuptty();
  1185.     read (0, &c, 1);
  1186.     return (chk_arrow (c & 0177)); /* just ASCII, please */
  1187. }
  1188.  
  1189. /* used to time out of a read */
  1190. static got_alrm;
  1191. static
  1192. on_alrm()
  1193. {
  1194.     got_alrm = 1;
  1195. }
  1196.  
  1197. /* see if c is the first of any of the curses arrow key sequences.
  1198.  * if it is, read the rest of the sequence, and return the hjkl code
  1199.  * that corresponds.
  1200.  * if no match, just return c.
  1201.  */
  1202. static 
  1203. chk_arrow (c)
  1204. register char c;
  1205. {
  1206.     register char *seq;
  1207.  
  1208.     if (c == *(seq = kl) || c == *(seq = kd) || c == *(seq = ku)
  1209.                          || c == *(seq = kr)) {
  1210.         char seqa[10]; /* maximum arrow escape sequence ever expected */
  1211.         int l = strlen(seq);
  1212.         seqa[0] = c;
  1213.         /* most arrow keys generate sequences starting with ESC. if so
  1214.          * c might just be a lone ESC; time out if so.
  1215.          */
  1216.         got_alrm=0;
  1217.         if (c == ESC) {
  1218.         signal (SIGALRM, on_alrm);
  1219.         alarm(1);
  1220.         }
  1221.         read (0, seqa+1, l-1);
  1222.         if (got_alrm == 0) {
  1223.         if (c == ESC)
  1224.             alarm(0);
  1225.         seqa[l] = '\0';
  1226.         if (strcmp (seqa, kl) == 0)
  1227.             return ('h');
  1228.         if (strcmp (seqa, kd) == 0)
  1229.             return ('j');
  1230.         if (strcmp (seqa, ku) == 0)
  1231.             return ('k');
  1232.         if (strcmp (seqa, kr) == 0)
  1233.             return ('l');
  1234.         }
  1235.     }
  1236.     return (c);
  1237. }
  1238.  
  1239. /* do whatever might be necessary to get the screen and/or tty back into shape.
  1240.  */
  1241. byetty()
  1242. {
  1243.     ioctl (0, TIOCSETP, &orig_sgtty);
  1244. }
  1245.  
  1246. static 
  1247. tload()
  1248. {
  1249.     extern char *getenv(), *tgetstr();
  1250.     extern char *UP, *BC;
  1251.     char *egetstr();
  1252.     static char tbuf[512];
  1253.     char rawtbuf[1024];
  1254.     char *tp;
  1255.     char *ptr;
  1256.  
  1257.     if (!(tp = getenv ("TERM"))) {
  1258.         printf ("Must have addressable cursor\n");
  1259.         exit(1);
  1260.     }
  1261.  
  1262.     if (!ttysetup) setuptty();
  1263.     if (tgetent (rawtbuf, tp) != 1) {
  1264.         printf ("can't find termcap for %s\n", tp);
  1265.         exit (1);
  1266.     }
  1267.     ptr = tbuf;
  1268.     ku = egetstr ("ku", &ptr);
  1269.     kd = egetstr ("kd", &ptr);
  1270.     kl = egetstr ("kl", &ptr);
  1271.     kr = egetstr ("kr", &ptr);
  1272.     cm = egetstr ("cm", &ptr);
  1273.     ce = egetstr ("ce", &ptr);
  1274.     cl = egetstr ("cl", &ptr);
  1275.     UP = egetstr ("up", &ptr);
  1276.     if (!tgetflag ("bs"))
  1277.         BC = egetstr ("bc", &ptr);
  1278.     tloaded = 1;
  1279. }
  1280.  
  1281. /* like tgetstr() but discard curses delay codes, for now anyways */
  1282. static char *
  1283. egetstr (name, sptr)
  1284. char *name;
  1285. char **sptr;
  1286. {
  1287.     extern char *tgetstr();
  1288.     register char c, *s;
  1289.  
  1290.     s = tgetstr (name, sptr);
  1291.     while ((c = *s) >= '0' && c <= '9')
  1292.         s += 1;
  1293.     return (s);
  1294. }
  1295.  
  1296. static
  1297. setuptty()
  1298. {
  1299.     extern ospeed;
  1300.     struct sgttyb sg;
  1301.  
  1302.     ioctl (0, TIOCGETP, &orig_sgtty);
  1303.     sg = orig_sgtty;
  1304.     ospeed = sg.sg_ospeed;
  1305.     sg.sg_flags &= ~ECHO;    /* do our own echoing */
  1306.     sg.sg_flags &= ~CRMOD;    /* leave CR and LF unchanged */
  1307.     sg.sg_flags |= XTABS;    /* no tabs with termcap */
  1308.     sg.sg_flags |= CBREAK;    /* wake up on each char but can still kill */
  1309.     ioctl (0, TIOCSETP, &sg);
  1310.     ttysetup = 1;
  1311. }
  1312. #endif
  1313.  
  1314. #ifdef LATTICE_C
  1315. #include <dos.h>
  1316.  
  1317.  
  1318. /* (ANSI: ESC [ r ; c F) (r/c are numbers given in ASCII digits)
  1319.  */
  1320. c_pos (r, c)
  1321. int r, c;
  1322. {
  1323.     printf ("%c[%d;%dF", ESC, r, c);
  1324. }
  1325.  
  1326. /* erase entire screen. (ANSI: ESC [ 2 j) */
  1327. c_erase()
  1328. {
  1329.     printf ("%c[2j", ESC);
  1330. }
  1331.  
  1332. /* erase to end of line. (ANSI: ESC [ K) */
  1333. c_eol()
  1334. {
  1335.     printf ("%c[K", ESC);
  1336. }
  1337.  
  1338. /* return 0 if there is a char that may be read without blocking, else -1 */
  1339. chk_char()
  1340. {
  1341.     return (kbhit() == 0 ? -1 : 0);
  1342. }
  1343.  
  1344. /* read the next char, blocking if necessary, and return it. don't echo.
  1345.  * map the arrow keys if we can too into hjkl
  1346.  */
  1347. read_char()
  1348. {
  1349.     int c;
  1350.     c = getch();
  1351.     if (c == 0) {
  1352.         /* get scan code; convert to direction hjkl if possible */
  1353.         c = getch();
  1354.         switch (c) {
  1355.         case 0x4b: c = 'h'; break;
  1356.         case 0x50: c = 'j'; break;
  1357.         case 0x48: c = 'k'; break;
  1358.         case 0x4d: c = 'l'; break;
  1359.         }
  1360.     }
  1361.     return (c);
  1362. }
  1363.  
  1364. /* do whatever might be necessary to get the screen and/or tty back into shape.
  1365.  */
  1366. byetty()
  1367. {
  1368. }
  1369. #endif
  1370.  
  1371. /* read up to max chars into buf, with cannonization.
  1372.  * add trailing '\0' (buf is really max+1 chars long).
  1373.  * return count of chars read (not counting '\0').
  1374.  * assume cursor is already positioned as desired.
  1375.  * ESC: return -1 immediately.
  1376.  */
  1377. read_line (buf, max)
  1378. char buf[];
  1379. int max;
  1380. {
  1381.     static char erase[] = "\b \b";
  1382.     int n, c;
  1383.     int done;
  1384.  
  1385. #ifdef UNIX
  1386.     if (!ttysetup) setuptty();
  1387. #endif
  1388.  
  1389.     for (done = 0, n = 0; !done; )
  1390.         switch (c = read_char()) {    /* does not echo */
  1391.         case 0177: case CNTRL('h'):    /* char erase */
  1392.         if (n > 0) {
  1393.             fputs (erase, stdout);
  1394.             n -= 1;
  1395.         }
  1396.         break;
  1397.         case CNTRL('u'):        /* line erase */
  1398.         while (n > 0) {
  1399.             fputs (erase, stdout);
  1400.             n -= 1;
  1401.         }
  1402.         break;
  1403.         case '\r':    /* EOL */
  1404.         done++;
  1405.         break;
  1406.         case ESC:            /* ESC to abort */
  1407.         return (-1);
  1408.         default:            /* echo and store */
  1409.         if (n >= max)
  1410.             putchar (CNTRL('g'));
  1411.         else {
  1412.             putchar (c);
  1413.             buf[n++] = c;
  1414.         }
  1415.         }
  1416.  
  1417.     buf[n] = '\0';
  1418.     return (n);
  1419. }
  1420. xXx
  1421.  
  1422.