home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / altsrcs / 2 / 2966 < prev    next >
Internet Message Format  |  1991-03-04  |  56KB

  1. From: guido@cwi.nl (Guido van Rossum)
  2. Newsgroups: alt.sources
  3. Subject: STDWIN 0.9.5, Part 05/19
  4. Message-ID: <3069@charon.cwi.nl>
  5. Date: 4 Mar 91 11:57:45 GMT
  6.  
  7. Archive-name: stdwin/part05
  8.  
  9. #! /bin/sh
  10. # This is a shell archive.  Remove anything before this line, then unpack
  11. # it by saving it into a file and typing "sh file".  To overwrite existing
  12. # files, type "sh file -c".  You can also feed this as standard input via
  13. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  14. # will see the following message at the end:
  15. #        "End of archive 5 (of 19)."
  16. # Contents:  Appls/klok/klok.c Conf/proto.os.bsd Ports/alfa/menu.c
  17. #   Ports/msdos/ptrm.c
  18. # Wrapped by guido@voorn.cwi.nl on Mon Mar  4 12:37:24 1991
  19. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  20. if test -f 'Appls/klok/klok.c' -a "${1}" != "-c" ; then 
  21.   echo shar: Will not clobber existing file \"'Appls/klok/klok.c'\"
  22. else
  23. echo shar: Extracting \"'Appls/klok/klok.c'\" \(17064 characters\)
  24. sed "s/^X//" >'Appls/klok/klok.c' <<'END_OF_FILE'
  25. X/* Analog clock with alarm.
  26. X   
  27. X   Displays the date at the top, a circular clock in the middle,
  28. X   and the alarm time at the bottom of the window.
  29. X   The clock has two hands.
  30. X   
  31. X   Resizing the window recomputes the items' positions and sizes.
  32. X   
  33. X   When the alarm goes off, the clock window is made current,
  34. X   the clock face is inverted for 5 minutes, and a beep is emitted
  35. X   each minute.  The alarm can be acknowledged explicitly, which
  36. X   silences it until the next time the alarm goes off.
  37. X   
  38. X   Dragging the hands of the clock can be used to set the time
  39. X   (and the date, if you care to drag around several times).
  40. X   The alarm is currently set through a dialog only.
  41. X
  42. X   TO DO:
  43. X       - make the display prettier (how??? everything I design gets ugly :-( )
  44. X    - display alarm time as tick mark?
  45. X    - improve the alarm setting procedure
  46. X    - add more general 'nag' and 'calendar'-like facilities
  47. X    - add a button to allow/disallow setting the time
  48. X    - add a way to change the date directly
  49. X    - turn it into a subroutine package like VT or editwin
  50. X    - organize the code top-down instead of bottom-up
  51. X*/
  52. X
  53. X#include "tools.h"
  54. X#include "stdwin.h"
  55. X
  56. X#include <ctype.h>
  57. X#include <math.h>
  58. X#include <time.h>
  59. X#include <sys/types.h>        /* For time_t, on some systems */
  60. X
  61. X#ifndef PI
  62. X#define PI 3.14159265359
  63. X#endif
  64. X
  65. X/* Alarm parametrizations */
  66. X
  67. X#ifndef DEF_ALARM
  68. X#define DEF_ALARM    -1    /* Initial setting of alarm */
  69. X#endif
  70. X#ifndef ALARMTIME
  71. X#define ALARMTIME    5    /* Alarm goes for this many minutes */
  72. X#endif
  73. X
  74. X/* Relative hand sizes */
  75. X
  76. X#define LITPERC        60    /* Little hand size (percent of radius) */
  77. X#define BIGPERC        80    /* Big hand size */
  78. X#define SECPERC        100    /* Seconds hand size */
  79. X
  80. X/* Menu items */
  81. X
  82. X#define SETALARM    0
  83. X#define CLEARALARM    1
  84. X#define OKALARM        2
  85. X#define SECONDSHAND    4
  86. X#define QUIT        6
  87. X
  88. X/* Global variables */
  89. X
  90. Xchar *progname = "klok";    /* Program name (for error messages) */
  91. Xchar *title;            /* Menu title (default capitalized progname) */
  92. XWINDOW *win;            /* Clock window */
  93. XMENU *mp;            /* Menu pointer */
  94. Xint centh, centv;        /* Clock center */
  95. Xint radius;            /* Clock radius */
  96. Xstruct tm curtime;        /* Current time/date */
  97. Xint alarm = DEF_ALARM;        /* Alarm time (hh*60 + mm); -1 if off */
  98. Xbool alarmed;            /* Is it alarm time? */
  99. Xbool okayed;            /* Has the current alarm been OK'ed? */
  100. Xbool excited;            /* == (alarmed && !okayed) */
  101. Xbool do_seconds;        /* Set if drawing 'seconds' hand */
  102. X
  103. X/* Force a redraw of the entire window */
  104. X
  105. Xchangeall()
  106. X{
  107. X    wchange(win, 0, 0, 10000, 10000);
  108. X}
  109. X
  110. X/* Compute the sine of an angle given in clock units
  111. X   (zero at 12 o'clock, full circle is 60).
  112. X   We cache the sine values in a table,
  113. X   since calling sin is too slow on some systems. */
  114. X
  115. Xdouble
  116. Xsine(i)
  117. X    int i;
  118. X{
  119. X    static double sines[15+1];
  120. X    static bool inited;
  121. X    
  122. X    if (!inited) {
  123. X        int k;
  124. X        inited = TRUE;
  125. X        for (k = 0; k <= 15; ++k)
  126. X            sines[k] = sin(k * PI/30);
  127. X    }
  128. X    i = i % 60;
  129. X    if (i < 0)
  130. X        i += 60;
  131. X    if (i <= 15)
  132. X        return sines[i];
  133. X    if (i <= 30)
  134. X        return sines[30-i];
  135. X    if (i <= 45)
  136. X        return -sines[i-30];
  137. X    return -sines[60-i];
  138. X}
  139. X
  140. X/* Compute the cosine (from the sine) */
  141. X
  142. Xdouble
  143. Xcosine(i)
  144. X    int i;
  145. X{
  146. X    return sine(i+15);
  147. X}
  148. X
  149. X/* Compute the absolute position of the endpoint of a line drawn at
  150. X   i minutes, whose length is a certain percentage of the radius */
  151. X
  152. Xvoid
  153. Xendpoint(i, perc, ph, pv)
  154. X    int i;        /* Minutes */
  155. X    int perc;    /* Percentage of length */
  156. X    int *ph, *pv;    /* Return values */
  157. X{
  158. X    double s = sine(i), c = cosine(i);
  159. X    
  160. X    *ph = centh + s*perc*radius/100 + 0.5;
  161. X    *pv = centv - c*perc*radius/100 + 0.5;
  162. X}
  163. X
  164. X/* Draw a mark at i minutes.
  165. X   Marks at hour positions are longer, every 3 hours even longer. */
  166. X
  167. Xvoid
  168. Xdrawmark(i)
  169. X    int i;
  170. X{
  171. X    int begh, begv;
  172. X    int endh, endv;
  173. X    int len;
  174. X    
  175. X    endpoint(i, 100, &endh, &endv);
  176. X    if (i % 5 != 0)
  177. X        len = 3;
  178. X    else if (i % 15 != 0)
  179. X        len = 8;
  180. X    else
  181. X        len = 19;
  182. X    endpoint(i, 100-len, &begh, &begv);
  183. X    wdrawline(begh, begv, endh, endv);
  184. X}
  185. X
  186. X/* Draw a hand at i minutes, whose length is a given percentage
  187. X   of the radius */
  188. X
  189. Xvoid
  190. Xdrawhand(i, perc)
  191. X    int i;
  192. X    int perc;
  193. X{
  194. X    int endh, endv;
  195. X    endpoint(i, perc, &endh, &endv);
  196. X    wdrawline(centh, centv, endh, endv);
  197. X}
  198. X
  199. X/* Draw a hand in XOR mode */
  200. X
  201. Xvoid
  202. Xxorhand(i, perc)
  203. X    int i;
  204. X    int perc;
  205. X{
  206. X    int endh, endv;
  207. X    endpoint(i, perc, &endh, &endv);
  208. X    wxorline(centh, centv, endh, endv);
  209. X}
  210. X
  211. X/* Draw the date in the top left corner */
  212. X
  213. Xvoid
  214. Xdrawdate(tp)
  215. X    struct tm *tp;
  216. X{
  217. X    char buf[100];
  218. X    
  219. X    sprintf(buf, "%02d/%02d/%02d", tp->tm_year % 100,
  220. X        tp->tm_mon+1, tp->tm_mday);
  221. X    werase(0, 0, 10000, centv - radius);
  222. X    wdrawtext(0, centv - radius - wlineheight(), buf, -1);
  223. X}
  224. X
  225. X/* Draw the alarm time in the bottom left corner */
  226. X
  227. Xvoid
  228. Xdrawalarm()
  229. X{
  230. X    char buf[100];
  231. X    
  232. X    sprintf(buf, "*%02d:%02d", alarm/60, alarm%60);
  233. X    wdrawtext(0, centv + radius, buf, -1);
  234. X}
  235. X
  236. X/* Compute the AM/MP/Noon/Midnight indicator character */
  237. X
  238. Xint
  239. Xampm(tp)
  240. X    struct tm *tp;
  241. X{
  242. X    if (tp->tm_min == 0 && tp->tm_hour%12 == 0) {
  243. X        if (tp->tm_hour == 12)
  244. X            return 'N';
  245. X        else
  246. X            return 'M';
  247. X    }
  248. X    else if (tp->tm_hour < 12)
  249. X        return 'A';
  250. X    else
  251. X        return 'P';
  252. X}
  253. X
  254. X/* Draw the AM/PM/Noon/Midnight indicator in the top right corner */
  255. X
  256. Xvoid
  257. Xdrawampm(c)
  258. X    int c;
  259. X{
  260. X    int dh = wcharwidth('M');
  261. X    int dv = wlineheight();
  262. X    int h = centh + radius - dh;
  263. X    int v = centv - radius - dv;
  264. X    
  265. X    werase(h, v, h+dh, v+dv);
  266. X    wdrawchar(h, v, c);
  267. X}
  268. X
  269. X#ifdef UGLY
  270. X
  271. X/* Draw a shaded square around the clock */
  272. X
  273. X#define SHOFF 4
  274. X
  275. Xvoid
  276. Xdrawborder()
  277. X{
  278. X    int d = radius * 10/9;
  279. X    int left = centh-d, top = centv-d, right = centh+d, bottom = centv+d;
  280. X    wdrawbox(left, top, right, bottom);
  281. X    wshade(right, top+4, right+4, bottom+4, 50);
  282. X    wshade(left+4, bottom, right, bottom+4, 50);
  283. X}
  284. X
  285. X/* Draw a shaded circle around the clock's face;
  286. X   the shadow is on the top left side, so the face appeares to
  287. X   be slightly *lower* than the surrounding material.
  288. X   Also a thin vertical line to indicate 6 and 12 o'clock. */
  289. X
  290. Xvoid
  291. Xdrawoutline()
  292. X{
  293. X    wdrawcircle(centh-1, centv-1, radius+2);
  294. X    wdrawelarc(centh-1, centv-1, radius+1, radius+1, 45-10, 45+180+10);
  295. X    wdrawelarc(centh-1, centv-1, radius  , radius  , 45+10, 45+180-10);
  296. X    wdrawline(centh, centv-radius, centh, centv+radius);
  297. X}
  298. X
  299. X#endif /*UGLY*/
  300. X
  301. X/* Compute the little hand position from hour, min */
  302. X
  303. Xint
  304. Xlittlehand(hour, min)
  305. X    int hour, min;
  306. X{
  307. X    return (hour*5 + (min+6)/12) % 60;
  308. X}
  309. X
  310. X/* Draw procedure */
  311. X
  312. Xvoid
  313. Xdrawproc(win, left, top, right, bottom)
  314. X    WINDOW *win;
  315. X{
  316. X    int i;
  317. X    
  318. X    /* Draw the fixed elements of the clock */
  319. X#ifdef UGLY
  320. X    drawborder();
  321. X    drawoutline();
  322. X#else
  323. X#ifdef macintosh
  324. X    wdrawcircle(centh+1, centv+1, radius+1);
  325. X#else
  326. X    wdrawcircle(centh, centv, radius);
  327. X#endif
  328. X    for (i = 0; i < 12; ++i)
  329. X        drawmark(i*5);            /* Hour marks */
  330. X#endif
  331. X    
  332. X    /* Draw the hands */
  333. X    drawhand(curtime.tm_min, BIGPERC);
  334. X    i = littlehand(curtime.tm_hour, curtime.tm_min);
  335. X    if (i != curtime.tm_min)
  336. X        xorhand(i, LITPERC);
  337. X    if (do_seconds)
  338. X        xorhand(curtime.tm_sec, SECPERC);
  339. X    
  340. X    /* Draw the other elements */
  341. X    drawdate(&curtime);
  342. X    drawampm(ampm(&curtime));
  343. X    if (alarm >= 0)
  344. X        drawalarm();
  345. X        
  346. X    /* Invert if the alarm is going */
  347. X    if (excited)
  348. X        winvert(0, 0, 10000, 10000);
  349. X}
  350. X
  351. X/* Compute the nearest clock angle corresponding to
  352. X   absolute position (h, v) */
  353. X
  354. Xint
  355. Xwhereis(h, v)
  356. X    int h, v;
  357. X{
  358. X    double dnew;
  359. X    
  360. X    h -= centh;
  361. X    v -= centv;
  362. X    if (h == 0 && v == 0)
  363. X        return 0;
  364. X    dnew = atan2((double)h, (double)(-v)) * 30.0 / PI;
  365. X    if (dnew < 0)
  366. X        dnew += 60.0;
  367. X    return ((int)(dnew + 0.5)) % 60;
  368. X}
  369. X
  370. X/* Show a change in time with minimal redrawing */
  371. X
  372. Xshowchange(old, new)
  373. X    struct tm *old, *new;
  374. X{
  375. X    int litold = littlehand(old->tm_hour, old->tm_min);
  376. X    int litnew = littlehand(new->tm_hour, new->tm_min);
  377. X    int newampm = ampm(new);
  378. X    
  379. X    wbegindrawing(win);
  380. X    
  381. X    if (do_seconds && old->tm_sec != new->tm_sec) {
  382. X        xorhand(old->tm_sec, SECPERC);
  383. X        xorhand(new->tm_sec, SECPERC);
  384. X    }
  385. X    
  386. X    if (old->tm_min != new->tm_min) {
  387. X        xorhand(old->tm_min, BIGPERC);
  388. X        xorhand(new->tm_min, BIGPERC);
  389. X    }
  390. X    
  391. X    if (litold != litnew ||
  392. X        litold == old->tm_min || litnew == new->tm_min) {
  393. X        if (litold != old->tm_min)
  394. X            xorhand(litold, LITPERC);
  395. X        if (litnew != new->tm_min)
  396. X            xorhand(litnew, LITPERC);
  397. X    }
  398. X    
  399. X    if (old->tm_mday != new->tm_mday)
  400. X        drawdate(new);
  401. X    
  402. X    if (newampm != ampm(old))
  403. X        drawampm(newampm);
  404. X    
  405. X    wenddrawing(win);
  406. X
  407. X}
  408. X
  409. X/* Leap year calculation.  Input is year - 1900 (but may be >= 100). */
  410. X
  411. Xint
  412. Xisleap(year)
  413. X    int year;
  414. X{
  415. X    year += 1900;
  416. X    
  417. X    return year%4 == 0 && (year%100 != 0 || year%400 == 0);
  418. X}
  419. X
  420. X/* Increment a time variable in minutes, and show the change */
  421. X
  422. Xvoid
  423. Xincrshowtime(tp, incr)
  424. X    struct tm *tp;
  425. X    int incr;
  426. X{
  427. X    struct tm old;
  428. X    static int mdays[12]=
  429. X        {31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
  430. X    
  431. X    mdays[1] = 28 + isleap(tp->tm_year);
  432. X    
  433. X    old = *tp;
  434. X    
  435. X    tp->tm_min += incr;
  436. X    
  437. X    while (tp->tm_min >= 60) {
  438. X        tp->tm_min -= 60;
  439. X        tp->tm_hour++;
  440. X        if (tp->tm_hour >= 24) {
  441. X            tp->tm_hour -= 24;
  442. X            tp->tm_mday++;
  443. X            tp->tm_wday = (tp->tm_wday + 1) % 7;
  444. X            if (tp->tm_mday > mdays[tp->tm_mon]) {
  445. X                tp->tm_mday = 1;
  446. X                tp->tm_mon++;
  447. X                if (tp->tm_mon >= 12) {
  448. X                    tp->tm_mon = 0;
  449. X                    tp->tm_year++;
  450. X                    mdays[1] = 28 + isleap(tp->tm_year);
  451. X                }
  452. X            }
  453. X        }
  454. X    }
  455. X    
  456. X    while (tp->tm_min < 0) {
  457. X        tp->tm_min += 60;
  458. X        tp->tm_hour--;
  459. X        if (tp->tm_hour < 0) {
  460. X            tp->tm_hour += 24;
  461. X            tp->tm_mday--;
  462. X            tp->tm_wday = (tp->tm_wday + 6) % 7;
  463. X            if (tp->tm_mday < 1) {
  464. X                tp->tm_mon--;
  465. X                if (tp->tm_mon < 0) {
  466. X                    tp->tm_mon = 11;
  467. X                    tp->tm_year--;
  468. X                    mdays[1] = 28 + isleap(tp->tm_year);
  469. X                }
  470. X                tp->tm_mday = mdays[tp->tm_mon];
  471. X            }
  472. X        }
  473. X    }
  474. X    
  475. X    showchange(&old, tp);
  476. X}
  477. X
  478. X/* Drag the little hand */
  479. X
  480. Xvoid
  481. Xdraglittlehand(h, v)
  482. X    int h, v;
  483. X{
  484. X    EVENT e;
  485. X    struct tm newtime;
  486. X    int i;
  487. X    
  488. X    newtime = curtime;
  489. X    wsettimer(win, 0);
  490. X    
  491. X    do {
  492. X        wgetevent(&e);
  493. X        if (e.type != WE_MOUSE_MOVE && e.type != WE_MOUSE_UP) {
  494. X            showchange(&newtime, &curtime);
  495. X            wungetevent(&e);
  496. X            return;
  497. X        }
  498. X        i = whereis(e.u.where.h, e.u.where.v) / 5;
  499. X        if ((i - newtime.tm_hour) % 12 != 0) {
  500. X            int diff = i - newtime.tm_hour;
  501. X            while (diff > 6)
  502. X                diff -= 12;
  503. X            while (diff < -6)
  504. X                diff += 12;
  505. X            incrshowtime(&newtime, diff*60);
  506. X        }
  507. X    } while (e.type != WE_MOUSE_UP);
  508. X    setdatetime(&newtime, FALSE);
  509. X    curtime = newtime;
  510. X}
  511. X
  512. X/* Drag the big hand */
  513. X
  514. Xvoid
  515. Xdragbighand(h, v)
  516. X    int h, v;
  517. X{
  518. X    EVENT e;
  519. X    struct tm newtime;
  520. X    int i;
  521. X    
  522. X    newtime = curtime;
  523. X    wsettimer(win, 0);
  524. X    
  525. X    do {
  526. X        wgetevent(&e);
  527. X        if (e.type != WE_MOUSE_MOVE && e.type != WE_MOUSE_UP) {
  528. X            showchange(&newtime, &curtime);
  529. X            wungetevent(&e);
  530. X            return;
  531. X        }
  532. X        i = whereis(e.u.where.h, e.u.where.v);
  533. X        if (i != newtime.tm_min) {
  534. X            int diff = i - newtime.tm_min;
  535. X            if (diff > 30)
  536. X                diff -= 60;
  537. X            else if (diff < -30)
  538. X                diff += 60;
  539. X            incrshowtime(&newtime, diff);
  540. X        }
  541. X    } while (e.type != WE_MOUSE_UP);
  542. X    setdatetime(&newtime, TRUE);
  543. X    curtime = newtime;
  544. X}
  545. X
  546. X/* Test whether the given position lies on the hand at the
  547. X   given clock angle with the given length percentage */
  548. X
  549. Xbool
  550. Xtesthand(h, v, pos, perc)
  551. X    int h, v;
  552. X    int pos;
  553. X    int perc;
  554. X{
  555. X    long dist2 = (h-centh)*(h-centh)+ (v-centv)*(v-centv);
  556. X    long length2 = ((long)radius*perc/100) * ((long)radius*perc/100);
  557. X    
  558. X    if (dist2 > length2)
  559. X        return FALSE;
  560. X    if ((whereis(h, v) - pos) % 60 != 0)
  561. X        return FALSE;
  562. X    return TRUE;
  563. X}
  564. X
  565. X/* Recompute the time and the alarm parameters.
  566. X   Called every minute, and when other parameters may have changed. */
  567. X
  568. Xvoid
  569. Xnewtime(flash)
  570. X    bool flash;
  571. X{
  572. X    struct tm oldtime;
  573. X    time_t now;
  574. X    bool wasalarmed;
  575. X    
  576. X    /* Save the old time displayed */
  577. X    oldtime = curtime;
  578. X    
  579. X    /* Get the current time */
  580. X    time(&now);
  581. X    curtime = *localtime(&now);
  582. X    
  583. X    /* Set the window timer to go off at the next tick */
  584. X    if (do_seconds) {
  585. X        wsettimer(win, 10);
  586. X    }
  587. X    else {
  588. X        if (curtime.tm_sec >= 59) {
  589. X            /* When we wake up just at the end of the minute,
  590. X               (which may happen if STDWIN isn't very precise),
  591. X               pretend it's a bit later, to avoid waking up
  592. X               again in a second */
  593. X            curtime.tm_sec -= 60;
  594. X            curtime.tm_min += 1;
  595. X        }
  596. X        wsettimer(win, 10 * (60 - curtime.tm_sec));
  597. X    }
  598. X    
  599. X    /* Check whether the alarm should go off */
  600. X    wasalarmed = alarmed;
  601. X    if (!wasalarmed)
  602. X        okayed = FALSE;
  603. X    if (alarm >= 0) {
  604. X        int a = alarm;
  605. X        int hhmm = curtime.tm_hour*60 + curtime.tm_min;
  606. X        if (hhmm < 60 && a >= 23*60)
  607. X            hhmm += 24*60; /* Correct for wrap-around */
  608. X        alarmed = hhmm >= a && hhmm < a+ALARMTIME;
  609. X    }
  610. X    else {
  611. X        alarmed = okayed = FALSE;
  612. X    }
  613. X    excited = alarmed && !okayed;
  614. X    if (excited) {
  615. X        if (!wasalarmed)
  616. X            wsetactive(win);
  617. X        wfleep();
  618. X    }
  619. X    if (excited || wasalarmed && !okayed)
  620. X        flash = TRUE;
  621. X    wmenuenable(mp, OKALARM, excited);
  622. X    
  623. X    /* Redraw the clock face or schedule a redraw */
  624. X    if (flash) {
  625. X        changeall();
  626. X    }
  627. X    else {
  628. X        showchange(&oldtime, &curtime);
  629. X    }
  630. X}
  631. X
  632. X/* Time-setting procedure by dragging the hands around */
  633. X
  634. Xvoid
  635. Xchangehand(h, v)
  636. X    int h, v;
  637. X{
  638. X    /* Test the little hand first, so that if the hands
  639. X       overlap, a click near the center implies the little
  640. X       hand and a click further away implies the big hand */
  641. X    if (testhand(h, v,
  642. X        littlehand(curtime.tm_hour, curtime.tm_min), LITPERC)) {
  643. X        /* Drag the little hand -- minutes stay unchanged */
  644. X        draglittlehand(h, v);
  645. X    }
  646. X    else if (testhand(h, v, curtime.tm_min, BIGPERC)) {
  647. X        /* Drag the big hand -- hours may change, too */
  648. X        dragbighand(h, v);
  649. X    }
  650. X    else {
  651. X        /* No hit -- make some noise */
  652. X        wfleep();
  653. X    }
  654. X    newtime(FALSE);
  655. X}
  656. X
  657. X/* Recompute the clock size and position
  658. X   and the time/alarm information.
  659. X   Called initially and when the window is resized. */
  660. X
  661. Xvoid
  662. Xgetallinfo()
  663. X{
  664. X    int width, height;
  665. X    
  666. X    wgetwinsize(win, &width, &height);
  667. X    centh = width/2;
  668. X    centv = height/2;
  669. X    radius = centv - wlineheight();
  670. X    CLIPMAX(radius, centh);
  671. X    newtime(TRUE);
  672. X}
  673. X
  674. X/* Set the alarm time from a string formatted as hhmm */
  675. X
  676. Xbool
  677. Xsetalarm(str)
  678. X    char *str;
  679. X{
  680. X    int al;
  681. X    
  682. X    if (str[0] == EOS || str[0] == '-' && str[1] == EOS) {
  683. X        alarm = -1;
  684. X        wmenuenable(mp, CLEARALARM, FALSE);
  685. X        return TRUE;
  686. X    }
  687. X    al = atoi(str);
  688. X    if (al < 0 || al > 2400 || al%60 >= 60)
  689. X        return FALSE;
  690. X    if (al == 2400)
  691. X        al = 0;
  692. X    alarm = (al/100)*60 + al%100;
  693. X    wmenuenable(mp, CLEARALARM, TRUE);
  694. X    return TRUE;
  695. X}
  696. X
  697. X/* Set up the menu */
  698. X
  699. Xvoid
  700. Xbuildmenu()
  701. X{
  702. X    wmenusetdeflocal(TRUE);
  703. X    mp = wmenucreate(1, "Klok");
  704. X    
  705. X    wmenuadditem(mp, "Set alarm...", 'S');
  706. X    wmenuadditem(mp, "Clear alarm", 'C');
  707. X    wmenuadditem(mp, "OK alarm", 'O');
  708. X    wmenuadditem(mp, "", -1);
  709. X    wmenuadditem(mp, "Seconds Hand", 'H');
  710. X    wmenuadditem(mp, "", -1);
  711. X    wmenuadditem(mp, "Quit", 'Q');
  712. X    
  713. X    wmenuenable(mp, CLEARALARM, alarm >= 0);
  714. X    wmenucheck(mp, SECONDSHAND, do_seconds);
  715. X}
  716. X
  717. X/* Handle a menu selection */
  718. X
  719. Xvoid
  720. Xdomenu(item)
  721. X    int item;
  722. X{
  723. X    bool flash = FALSE;
  724. X    
  725. X    switch (item) {
  726. X    case SETALARM: {
  727. X        char buf[6];
  728. X        if (alarm < 0)
  729. X            buf[0] = EOS;
  730. X        else
  731. X            sprintf(buf, "%02d%02d", alarm/60, alarm%60);
  732. X        if (!waskstr("Set alarm:", buf, sizeof buf))
  733. X            return;
  734. X        if (!setalarm(buf))
  735. X            wmessage("Invalid alarm (must be hhmm)");
  736. X        okayed = FALSE;
  737. X        flash = TRUE;
  738. X        break;
  739. X        }
  740. X    case CLEARALARM:
  741. X        if (alarm >= 0) {
  742. X            setalarm("");
  743. X            flash = TRUE;
  744. X        }
  745. X        break;
  746. X    case OKALARM:
  747. X        if (excited) {
  748. X            flash = okayed = TRUE;
  749. X        }
  750. X        break;
  751. X    case SECONDSHAND:
  752. X        do_seconds = !do_seconds;
  753. X        wmenucheck(mp, SECONDSHAND, do_seconds);
  754. X        wbegindrawing(win);
  755. X        xorhand(curtime.tm_sec, SECPERC);
  756. X        wenddrawing(win);
  757. X        break;
  758. X    case QUIT:
  759. X        wclose(win);
  760. X        wdone();
  761. X        exit(0);
  762. X        break;
  763. X    }
  764. X    newtime(flash);
  765. X}
  766. X
  767. X#ifndef macintosh
  768. X/* Print usage message and exit; called for command line errors */
  769. X
  770. Xvoid
  771. Xusage()
  772. X{
  773. X    wdone();
  774. X    fprintf(stderr,
  775. X        "usage: %s [-s] [-m] [-a hhmm] [-t title]\n", progname);
  776. X    exit(2);
  777. X}
  778. X#endif
  779. X
  780. X/* Main program */
  781. X
  782. Xmain(argc, argv)
  783. X    int argc;
  784. X    char **argv;
  785. X{
  786. X    /* Initialize */
  787. X    winitargs(&argc, &argv);
  788. X    buildmenu(); /* Must be done before setalarm is called */
  789. X    
  790. X    /* Find out program name */
  791. X    if (argc > 0) {
  792. X        progname = strrchr(argv[0], '/');
  793. X        if (progname == NULL)
  794. X            progname = argv[0];
  795. X        else
  796. X            ++progname;
  797. X    }
  798. X    
  799. X#ifndef macintosh
  800. X    /* Parse command line */
  801. X    for (;;) {
  802. X        int c = getopt(argc, argv, "msa:t:");
  803. X        if (c == EOF)
  804. X            break;
  805. X        switch (c) {
  806. X        case 's':
  807. X            do_seconds = TRUE;
  808. X            break;
  809. X        case 'm':
  810. X            do_seconds = FALSE;
  811. X            break;
  812. X        case 'a':
  813. X            if (!setalarm(optarg))
  814. X                usage();
  815. X            break;
  816. X        case 't':
  817. X            title = optarg;
  818. X            break;
  819. X        default:
  820. X            usage();
  821. X            /*NOTREACHED*/
  822. X        }
  823. X    }
  824. X    wmenucheck(mp, SECONDSHAND, do_seconds);
  825. X#endif
  826. X    
  827. X    /* Create the window */
  828. X    wsetdefwinsize(120, 120);
  829. X    win = wopen(title == NULL ? progname : title, drawproc);
  830. X    wmenuattach(win, mp);
  831. X    
  832. X    /* Main loop */
  833. X    getallinfo();
  834. X    for (;;) {
  835. X        EVENT e;
  836. X        wgetevent(&e);
  837. X        
  838. X        switch (e.type) {
  839. X        
  840. X        case WE_MOUSE_DOWN:
  841. X            if (excited)
  842. X                domenu(OKALARM);
  843. X            else
  844. X                changehand(e.u.where.h, e.u.where.v);
  845. X            break;
  846. X        
  847. X        case WE_MENU:
  848. X            if (e.u.m.id == 1)
  849. X                domenu(e.u.m.item);
  850. X            break;
  851. X        
  852. X        case WE_CHAR:
  853. X            if (excited)
  854. X                break;
  855. X            switch (e.u.character) {
  856. X            case 's':
  857. X            case 'S':
  858. X                domenu(SETALARM);
  859. X                break;
  860. X            case 'c':
  861. X            case 'C':
  862. X                domenu(CLEARALARM);
  863. X                break;
  864. X            case 'h':
  865. X            case 'H':
  866. X                domenu(SECONDSHAND);
  867. X                break;
  868. X            case 'q':
  869. X            case 'Q':
  870. X                domenu(QUIT);
  871. X                break;
  872. X            }
  873. X            break;
  874. X        
  875. X        case WE_COMMAND:
  876. X            switch (e.u.command) {
  877. X            case WC_RETURN:
  878. X                newtime(FALSE);
  879. X                break;
  880. X            case WC_CLOSE:
  881. X            case WC_CANCEL:
  882. X                domenu(QUIT);
  883. X                break;
  884. X            }
  885. X            break;
  886. X
  887. X        case WE_CLOSE:
  888. X            domenu(QUIT);
  889. X            break;
  890. X        
  891. X        case WE_SIZE:
  892. X            getallinfo();
  893. X            break;
  894. X        
  895. X        case WE_TIMER:
  896. X            newtime(FALSE);
  897. X            break;
  898. X        
  899. X        }
  900. X    }
  901. X}
  902. END_OF_FILE
  903. if test 17064 -ne `wc -c <'Appls/klok/klok.c'`; then
  904.     echo shar: \"'Appls/klok/klok.c'\" unpacked with wrong size!
  905. fi
  906. # end of 'Appls/klok/klok.c'
  907. fi
  908. if test -f 'Conf/proto.os.bsd' -a "${1}" != "-c" ; then 
  909.   echo shar: Will not clobber existing file \"'Conf/proto.os.bsd'\"
  910. else
  911. echo shar: Extracting \"'Conf/proto.os.bsd'\" \(143 characters\)
  912. sed "s/^X//" >'Conf/proto.os.bsd' <<'END_OF_FILE'
  913. X
  914. X#
  915. X# Definitions pertaining to BSD (4.3)
  916. X#
  917. X
  918. XOS=        bsd
  919. XRANLIB=        ranlib
  920. X
  921. X# MKDEP is defined in proto.arch.*
  922. X
  923. XLIBTERMCAP=    -ltermcap
  924. XLIBX11=        -lX11
  925. END_OF_FILE
  926. if test 143 -ne `wc -c <'Conf/proto.os.bsd'`; then
  927.     echo shar: \"'Conf/proto.os.bsd'\" unpacked with wrong size!
  928. fi
  929. # end of 'Conf/proto.os.bsd'
  930. fi
  931. if test -f 'Ports/alfa/menu.c' -a "${1}" != "-c" ; then 
  932.   echo shar: Will not clobber existing file \"'Ports/alfa/menu.c'\"
  933. else
  934. echo shar: Extracting \"'Ports/alfa/menu.c'\" \(10366 characters\)
  935. sed "s/^X//" >'Ports/alfa/menu.c' <<'END_OF_FILE'
  936. X/* TERMCAP STDWIN -- MENUS. */
  937. X
  938. X#include "alfa.h"
  939. X
  940. Xstatic bool deflocal= FALSE;    /* Default menu state */
  941. X
  942. Xstatic struct menubar gmenus;    /* All global menus */
  943. Xstatic struct menubar lmenus;    /* All local menus */
  944. X
  945. Xstatic MENU *sysmenu;        /* Window selection commands */
  946. Xstatic MENU *curmenu;
  947. X
  948. Xstatic void
  949. Xaddtobar(mbp, mp)
  950. X    struct menubar *mbp;
  951. X    MENU *mp;
  952. X{
  953. X    int i;
  954. X    
  955. X    for (i= 0; i < mbp->nmenus; ++i) {
  956. X        if (mp == mbp->menulist[i])
  957. X            return; /* Already attached */
  958. X    }
  959. X    L_APPEND(mbp->nmenus, mbp->menulist, MENU *, mp);
  960. X}
  961. X
  962. Xstatic void
  963. Xdelfrombar(mbp, mp)
  964. X    struct menubar *mbp;
  965. X    MENU *mp;
  966. X{
  967. X    int i;
  968. X    
  969. X    for (i= 0; i < mbp->nmenus; ++i) {
  970. X        if (mp == mbp->menulist[i]) {
  971. X            L_REMOVE(mbp->nmenus, mbp->menulist,
  972. X                MENU *, i);
  973. X            break;
  974. X        }
  975. X    }
  976. X}
  977. X
  978. X_winitmenus()
  979. X{
  980. X    sysmenu= wmenucreate(0, "Windows");
  981. X    wmenuadditem(sysmenu, "Previous Window", -1);
  982. X    wmenuadditem(sysmenu, "Next Window", -1);
  983. X#ifndef EM
  984. X    /* Somehow, Euromath doesn't like this?!? */
  985. X    wmenuadditem(sysmenu, "Close Window", -1);
  986. X    wmenuadditem(sysmenu, "(left)", -1);
  987. X    wmenuadditem(sysmenu, "(right)", -1);
  988. X    wmenuadditem(sysmenu, "(up)", -1);
  989. X    wmenuadditem(sysmenu, "(down)", -1);
  990. X    wmenuadditem(sysmenu, "(cancel)", -1);
  991. X    wmenuadditem(sysmenu, "(backspace)", -1);
  992. X    wmenuadditem(sysmenu, "(tab)", -1);
  993. X    wmenuadditem(sysmenu, "(return)", -1);
  994. X#endif
  995. X    /* Shortcuts are compiled in the key map! */
  996. X}
  997. X
  998. XMENU *
  999. Xwmenucreate(id, title)
  1000. X    int id;
  1001. X    char *title;
  1002. X{
  1003. X    MENU *mp= ALLOC(MENU);
  1004. X    
  1005. X    if (mp == NULL)
  1006. X        return NULL;
  1007. X    mp->id= id;
  1008. X    mp->title= strdup(title);
  1009. X    mp->local= deflocal;
  1010. X    mp->dirty= TRUE;
  1011. X    mp->left= mp->right= 0;
  1012. X    L_INIT(mp->nitems, mp->itemlist);
  1013. X    addtobar(mp->local ? &lmenus : &gmenus, mp);
  1014. X    if (!mp->local)
  1015. X        menubarchanged();
  1016. X    return mp;
  1017. X}
  1018. X
  1019. Xvoid
  1020. Xwmenudelete(mp)
  1021. X    MENU *mp;
  1022. X{
  1023. X    int i;
  1024. X    
  1025. X    if (mp->local) {
  1026. X        for (i= 0; i < MAXWINDOWS; ++i) {
  1027. X            if (winlist[i].open)
  1028. X                delfrombar(&winlist[i].mbar, mp);
  1029. X        }
  1030. X    }
  1031. X    delfrombar(mp->local ? &lmenus : &gmenus, mp);
  1032. X    for (i= 0; i < mp->nitems; ++i) {
  1033. X        FREE(mp->itemlist[i].text);
  1034. X        FREE(mp->itemlist[i].shortcut);
  1035. X    }
  1036. X    L_DEALLOC(mp->nitems, mp->itemlist);
  1037. X    FREE(mp);
  1038. X    menubarchanged();
  1039. X}
  1040. X
  1041. Xint
  1042. Xwmenuadditem(mp, text, shortcut)
  1043. X    MENU *mp;
  1044. X    char *text;
  1045. X    int shortcut;
  1046. X{
  1047. X    struct item it;
  1048. X    
  1049. X    mp->dirty= TRUE;
  1050. X    it.text= strdup(text);
  1051. X#ifdef EM
  1052. X/* need to add the shortcut now, otherwise it will be taken from
  1053. X   the keymap whenever the menu is displayed, which might be after
  1054. X   opening another window and overwriting the keymap entry.
  1055. X   In the AddMenuEntry code I overwrite the shortcut anyway. */
  1056. X/* I don't understand this --Guido */
  1057. X    if(shortcut >= 32) {
  1058. X        it.shortcut=(char *)malloc(8);    
  1059. X        sprintf(it.shortcut,"ESC %c", shortcut);
  1060. X    } else 
  1061. X#endif
  1062. X    it.shortcut= NULL;
  1063. X    it.enabled= (text != NULL && *text != EOS);
  1064. X    it.checked= FALSE;
  1065. X    L_APPEND(mp->nitems, mp->itemlist, struct item, it);
  1066. X    if (shortcut >= 0)
  1067. X        wsetmetakey(mp->id, mp->nitems-1, shortcut);
  1068. X    return mp->nitems-1;
  1069. X}
  1070. X
  1071. Xvoid
  1072. Xwmenusetitem(mp, item, text)
  1073. X    MENU *mp;
  1074. X    int item;
  1075. X    char *text;
  1076. X{
  1077. X    if (item < 0 || item >= mp->nitems)
  1078. X        return;
  1079. X    mp->dirty= TRUE;
  1080. X    FREE(mp->itemlist[item].text);
  1081. X    mp->itemlist[item].text= strdup(text);
  1082. X    mp->itemlist[item].enabled= (text != NULL && *text != EOS);
  1083. X}
  1084. X
  1085. Xvoid
  1086. Xwmenuenable(mp, item, flag)
  1087. X    MENU *mp;
  1088. X    int item;
  1089. X    int flag;
  1090. X{
  1091. X    if (item < 0 || item >= mp->nitems)
  1092. X        return;
  1093. X    mp->itemlist[item].enabled= flag;
  1094. X}
  1095. X
  1096. Xvoid
  1097. Xwmenucheck(mp, item, flag)
  1098. X    MENU *mp;
  1099. X    int item;
  1100. X    int flag;
  1101. X{
  1102. X    if (item < 0 || item >= mp->nitems)
  1103. X        return;
  1104. X    mp->itemlist[item].checked= flag;
  1105. X}
  1106. X
  1107. Xvoid
  1108. Xwmenuattach(win, mp)
  1109. X    WINDOW *win;
  1110. X    MENU *mp;
  1111. X{
  1112. X    if (!mp->local)
  1113. X        return;
  1114. X    addtobar(&win->mbar, mp);
  1115. X    if (win == front)
  1116. X        menubarchanged();
  1117. X}
  1118. X
  1119. Xvoid
  1120. Xwmenudetach(win, mp)
  1121. X    WINDOW *win;
  1122. X    MENU *mp;
  1123. X{
  1124. X    if (!mp->local)
  1125. X        return;
  1126. X    delfrombar(&win->mbar, mp);
  1127. X    if (win == front)
  1128. X        menubarchanged();
  1129. X}
  1130. X
  1131. Xvoid
  1132. Xwmenusetdeflocal(local)
  1133. X    bool local;
  1134. X{
  1135. X    deflocal= local;
  1136. X}
  1137. X
  1138. X/* Interface routines for the rest of the library. */
  1139. X
  1140. Xvoid
  1141. Xinitmenubar(mb)
  1142. X    struct menubar *mb;
  1143. X{
  1144. X    L_INIT(mb->nmenus, mb->menulist);
  1145. X}
  1146. X
  1147. Xvoid
  1148. Xkillmenubar(mb)
  1149. X    struct menubar *mb;
  1150. X{
  1151. X    L_DEALLOC(mb->nmenus, mb->menulist);
  1152. X}
  1153. X
  1154. Xvoid
  1155. Xdrawmenubar() /* This is part of the syswin draw procedure! */
  1156. X{
  1157. X    WINDOW *win= front;
  1158. X    char buf[256];
  1159. X    int k= 0;
  1160. X    int i;
  1161. X    
  1162. X    buf[0]= EOS;
  1163. X    for (i= 0; i < gmenus.nmenus; ++i)
  1164. X        k= bufappend(buf, k, gmenus.menulist[i]);
  1165. X    if (win != NULL) {
  1166. X        for (i= 0; i < win->mbar.nmenus; ++i)
  1167. X            k= bufappend(buf, k, win->mbar.menulist[i]);
  1168. X    }
  1169. X    wdrawtext(0, 0, buf, -1);
  1170. X}
  1171. X
  1172. Xstatic int
  1173. Xbufappend(buf, pos, mp)
  1174. X    char *buf;
  1175. X    int pos;
  1176. X    MENU *mp;
  1177. X{
  1178. X    if (pos > 0) {
  1179. X        buf[pos++]= ' ';
  1180. X        buf[pos++]= ' ';
  1181. X    }
  1182. X    mp->left= pos;
  1183. X    strcpy(buf+pos, mp->title);
  1184. X    pos += strlen(buf+pos);
  1185. X    mp->right= pos;
  1186. X    return pos;
  1187. X}
  1188. X
  1189. X/* TO DO:
  1190. X   - highlight current menu title, current menu item
  1191. X   - remember last menu and item
  1192. X   - Allow GOTO to select menus or menu items
  1193. X     (m-down on mbar opens the menu; m-up on item selects the item)
  1194. X*/
  1195. X
  1196. Xstatic void menudraw(), menuitemdraw(), menucalcwidth();
  1197. Xstatic bool handleevt(), handlecmd(), handlemenu();
  1198. Xstatic int calcleft();
  1199. X
  1200. Xstatic leftblank;
  1201. X
  1202. Xstatic bool        curlocal;
  1203. Xstatic struct menubar *    curmbar;
  1204. Xstatic int        curimenu;
  1205. Xstatic int        curitem;
  1206. Xstatic int        lowest;
  1207. X
  1208. Xstatic bool
  1209. Xfirstmenu()
  1210. X{
  1211. X    curlocal= FALSE;
  1212. X    curmbar= &gmenus;
  1213. X    curimenu= 0;
  1214. X    
  1215. X    if (curmbar->nmenus == 0) {
  1216. X        curmbar= &lmenus;
  1217. X        curlocal= TRUE;
  1218. X        if (curmbar->nmenus == 0) {
  1219. X            wmessage("No menus defined");
  1220. X            return FALSE;
  1221. X        }
  1222. X    }
  1223. X    curmenu= curmbar->menulist[curimenu];
  1224. X    curitem= 0;
  1225. X    menudraw();
  1226. X    return TRUE;
  1227. X}
  1228. X
  1229. Xstatic void
  1230. Xnextmenu()
  1231. X{
  1232. X    WINDOW *win=front; /* added mcv */
  1233. X/* the menus are now taken from the window's menubar, instead
  1234. X   of the menubar for *all* local menus */
  1235. X
  1236. X    ++curimenu;
  1237. X    while (curimenu >= curmbar->nmenus) {
  1238. X        curlocal= !curlocal;
  1239. X        curmbar= curlocal ? 
  1240. X                 &win->mbar /* changed mcv, was: &lmenus*/ : 
  1241. X                 &gmenus;
  1242. X        curimenu= 0;
  1243. X    }
  1244. X    curmenu= curmbar->menulist[curimenu];
  1245. X    curitem= 0;
  1246. X    menudraw();
  1247. X}
  1248. X
  1249. Xstatic void
  1250. Xprevmenu()
  1251. X{
  1252. X    WINDOW *win=front;  /* added mcv */
  1253. X/* the menus are now taken from the window's menubar, instead
  1254. X   of the menubar for *all* local menus */
  1255. X
  1256. X    --curimenu;
  1257. X    while (curimenu < 0) {
  1258. X        curlocal= !curlocal;
  1259. X        curmbar= curlocal ? 
  1260. X                 &win->mbar /* changed mcv, was: &lmenus*/ : 
  1261. X                 &gmenus;
  1262. X        curimenu= curmbar->nmenus - 1;
  1263. X    }
  1264. X    curmenu= curmbar->menulist[curimenu];
  1265. X    curitem= 0;
  1266. X    menudraw();
  1267. X}
  1268. X
  1269. Xstatic void
  1270. Xnextitem()
  1271. X{
  1272. X    ++curitem;
  1273. X    if (curitem >= curmenu->nitems)
  1274. X        curitem= 0;
  1275. X    trmsync(curitem+1, curmenu->left);
  1276. X}
  1277. X
  1278. Xstatic void
  1279. Xprevitem()
  1280. X{
  1281. X    --curitem;
  1282. X    if (curitem < 0)
  1283. X        curitem= curmenu->nitems - 1;
  1284. X    trmsync(curitem+1, curmenu->left);
  1285. X}
  1286. X
  1287. Xstatic void
  1288. Xselectitem(ep)
  1289. X    EVENT *ep;
  1290. X{
  1291. X    ep->type= WE_NULL;
  1292. X    if (curitem >= curmenu->nitems || !curmenu->itemlist[curitem].enabled)
  1293. X        return;
  1294. X    ep->type= WE_MENU;
  1295. X    ep->u.m.id= curmenu->id;
  1296. X    ep->u.m.item= curitem;
  1297. X}
  1298. X
  1299. Xvoid
  1300. Xmenuselect(ep)
  1301. X    EVENT *ep;
  1302. X{
  1303. X    leftblank= columns;
  1304. X    lowest= 0;
  1305. X    wmessage((char *)NULL);
  1306. X    if (!firstmenu())
  1307. X        return;
  1308. X    for (;;) {
  1309. X        wsysevent(ep, 1);
  1310. X        if (handleevt(ep))
  1311. X            break;
  1312. X    }
  1313. X}
  1314. X
  1315. Xstatic bool
  1316. Xhandleevt(ep)
  1317. X    EVENT *ep;
  1318. X{
  1319. X    switch (ep->type) {
  1320. X    
  1321. X    case WE_MENU:
  1322. X        return handlemenu(ep);
  1323. X    
  1324. X    case WE_COMMAND:
  1325. X        return handlecmd(ep);
  1326. X    
  1327. X    default:
  1328. X        trmbell();
  1329. X        return FALSE;
  1330. X    
  1331. X    }
  1332. X}
  1333. X
  1334. Xstatic bool
  1335. Xhandlecmd(ep)
  1336. X    EVENT *ep;
  1337. X{
  1338. X    switch (ep->u.command) {
  1339. X    
  1340. X    default:
  1341. X        trmbell();
  1342. X        return FALSE;
  1343. X    
  1344. X    case WC_RETURN:
  1345. X        selectitem(ep);
  1346. X        if (curmenu == sysmenu)
  1347. X            wsyscommand(ep);
  1348. X        return TRUE;
  1349. X    
  1350. X    case WC_LEFT:
  1351. X        prevmenu();
  1352. X        break;
  1353. X    
  1354. X    case WC_RIGHT:
  1355. X        nextmenu();
  1356. X        break;
  1357. X    
  1358. X    case WC_UP:
  1359. X        previtem();
  1360. X        break;
  1361. X    
  1362. X    case WC_DOWN:
  1363. X        nextitem();
  1364. X        break;
  1365. X    
  1366. X    case WC_CANCEL:
  1367. X        ep->type= WE_NULL;
  1368. X        return TRUE;
  1369. X    
  1370. X    }
  1371. X    return FALSE;
  1372. X}
  1373. X
  1374. Xstatic bool
  1375. Xhandlemenu(ep)
  1376. X    EVENT *ep;
  1377. X{
  1378. X    if (ep->u.m.id != 0)
  1379. X        return TRUE;
  1380. X    switch (ep->u.m.item) {
  1381. X    
  1382. X    case SUSPEND_PROC:
  1383. X        _wsuspend();
  1384. X        menudraw();
  1385. X        break;
  1386. X    
  1387. X    case REDRAW_SCREEN:
  1388. X        _wredraw();
  1389. X        menudraw();
  1390. X        break;
  1391. X    
  1392. X    case MENU_CALL:
  1393. X        ep->type= WE_NULL;
  1394. X        return TRUE;
  1395. X
  1396. X    default:
  1397. X        if (ep->u.m.item <= LAST_CMD) {
  1398. X            wsyscommand(ep);
  1399. X            if (ep->type == WE_COMMAND)
  1400. X                return handlecmd(ep);
  1401. X            else
  1402. X                return TRUE;
  1403. X        }
  1404. X        else {
  1405. X            trmbell();
  1406. X            return FALSE;
  1407. X        }
  1408. X    
  1409. X    }
  1410. X    return FALSE;
  1411. X}
  1412. X
  1413. Xstatic void
  1414. Xmenudraw()
  1415. X{
  1416. X    MENU *mp= curmenu;
  1417. X    int left;
  1418. X    int width;
  1419. X    int i;
  1420. X    
  1421. X    wupdate(syswin);
  1422. X    if (mp->dirty)
  1423. X        menucalcwidth(mp);
  1424. X    left= calcleft(mp);
  1425. X    width= mp->maxwidth;
  1426. X    if (left + width > columns)
  1427. X        width= columns - left;
  1428. X    for (i= 0; i < mp->nitems; ++i)
  1429. X        menuitemdraw(i+1, left, &mp->itemlist[i], width);
  1430. X    if (i+1 > lowest) {
  1431. X        lowest= i+1;
  1432. X        if (lowest < lines)
  1433. X            uptodate[lowest]= FALSE;
  1434. X    }
  1435. X    trmputdata(i+1, lowest, 0, "");
  1436. X    leftblank= left;
  1437. X    trmsync(curitem+1, mp->left);
  1438. X}
  1439. X
  1440. Xstatic int
  1441. Xcalcleft(mp)
  1442. X    MENU *mp;
  1443. X{
  1444. X    int left= columns - mp->maxwidth;
  1445. X    
  1446. X    if (left > mp->left)
  1447. X        left= mp->left;
  1448. X    if (left < 0)
  1449. X        left= 0;
  1450. X    if (left-3 < leftblank) {
  1451. X        leftblank= left-3;
  1452. X        if (leftblank < 4)
  1453. X            leftblank= 0;
  1454. X    }
  1455. X    return left;
  1456. X}
  1457. X
  1458. Xstatic void
  1459. Xmenuitemdraw(line, left, ip, width)
  1460. X    int line, left;
  1461. X    struct item *ip;
  1462. X    int width;
  1463. X{
  1464. X    char buf[256];
  1465. X    int margin= left-leftblank;
  1466. X    
  1467. X    buf[0]= EOS;
  1468. X    if (ip->text != NULL && *ip->text != EOS) {
  1469. X        int space;
  1470. X        char *p= buf;
  1471. X        for (space= margin; space-- > 0; )
  1472. X            *p++ = ' ';
  1473. X        if (ip->checked && margin >= 2)
  1474. X            p[-2]= '*';
  1475. X        strcpy(p, ip->text);
  1476. X        p += strlen(p);
  1477. X        if (!ip->enabled && margin >= 1 &&
  1478. X            ip->text != NULL && ip->text[0] != EOS) {
  1479. X            buf[margin-1]= '(';
  1480. X            *p++= ')';
  1481. X            *p= '\0';
  1482. X        }
  1483. X        if (ip->shortcut != NULL && *ip->shortcut != EOS) {
  1484. X            space= width - (p - buf - margin)
  1485. X                - strlen(ip->shortcut);
  1486. X            if (space <= 0)
  1487. X                space= 2;
  1488. X            while (--space >= 0)
  1489. X                *p++ = ' ';
  1490. X            strcpy(p, ip->shortcut);
  1491. X        }
  1492. X    }
  1493. X    /* This was added because brackets and stars from disabled/marked
  1494. X       items on the first menu (after the sysmenu) weren't removed
  1495. X       from the screen.  I haven't tried to fix this in a more
  1496. X       efficient manner. */
  1497. X    trmputdata(line, line, 0, "");
  1498. X    trmputdata(line, line, leftblank, buf);
  1499. X    uptodate[line]= FALSE;
  1500. X}
  1501. X
  1502. Xstatic void
  1503. Xmenucalcwidth(mp)
  1504. X    MENU *mp;
  1505. X{
  1506. X    int i;
  1507. X    int width= 0;
  1508. X    
  1509. X    for (i= 0; i < mp->nitems; ++i) {
  1510. X        struct item *ip= &mp->itemlist[i];
  1511. X        char *text= ip->text;
  1512. X        if (text != NULL && *text != EOS) {
  1513. X            int w= strlen(text);
  1514. X            if (ip->shortcut == NULL) {
  1515. X                char buf[256];
  1516. X                getbindings(buf, mp->id, i);
  1517. X                ip->shortcut= strdup(buf);
  1518. X            }
  1519. X            if (ip->shortcut != NULL && *ip->shortcut != EOS)
  1520. X                w += 2 + strlen(ip->shortcut);
  1521. X            if (w > width)
  1522. X                width= w;
  1523. X        }
  1524. X    }
  1525. X    mp->maxwidth= width;
  1526. X    mp->dirty= FALSE;
  1527. X}
  1528. END_OF_FILE
  1529. if test 10366 -ne `wc -c <'Ports/alfa/menu.c'`; then
  1530.     echo shar: \"'Ports/alfa/menu.c'\" unpacked with wrong size!
  1531. fi
  1532. # end of 'Ports/alfa/menu.c'
  1533. fi
  1534. if test -f 'Ports/msdos/ptrm.c' -a "${1}" != "-c" ; then 
  1535.   echo shar: Will not clobber existing file \"'Ports/msdos/ptrm.c'\"
  1536. else
  1537. echo shar: Extracting \"'Ports/msdos/ptrm.c'\" \(23047 characters\)
  1538. sed "s/^X//" >'Ports/msdos/ptrm.c' <<'END_OF_FILE'
  1539. X/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1986. */
  1540. X
  1541. X/*
  1542. X * ibm Pc virtual TeRMinal package.
  1543. X *
  1544. X * (Under reconstruction by Guido!)
  1545. X *
  1546. X * An implementation of the VTRM interface for MS-DOS machines.
  1547. X *
  1548. X * This code supports two modes of accessing the screen.
  1549. X * The first one (BIOS) will be used, unless the user overwrites this
  1550. X * by setting the SCREEN environment variable.
  1551. X * This variable can also be used to convey a screen size that differs
  1552. X * from the default 25 lines and 80 columns. See below.
  1553. X *
  1554. X * The two modes are:
  1555. X *
  1556. X * 1) IBM BIOS interrupt 10 hex, video io.
  1557. X *    (See IBM PC XT Technical Reference 6936833, May 1983,
  1558. X *     Appendix A, pages A46-A47).
  1559. X *    This is what you really want to use, since it's the only one that
  1560. X *    can decently scroll. It cannot insert or delete characters, so
  1561. X *    most optimisations from vtrm.c are useless and taken out.
  1562. X *    Unfortunately, not every PC-compatible machine supports this BIOS
  1563. X *    interrupt, so for these unlucky souls there is the following escape:
  1564. X *
  1565. X * 2) The ANSI.SYS driver.
  1566. X *    (See IBM MS-DOS 6936839, Jan 1983, Version 2.00, Chapter 13.)
  1567. X *    (Some compatibles don't have a separate ANSI.SYS driver but do the
  1568. X *    same escape interpretation by default.)
  1569. X *    This works reasonably, apart from scrolling downward, or part of
  1570. X *    the screen, which is clumsy.
  1571. X *    (The ANSI standard provides an escape sequence for scrolling
  1572. X *    but ANSI.SYS does not support it, nor any other way of scrolling.)
  1573. X *
  1574. X * The rest of the interface is the same as described in vtrm.c,
  1575. X * with the following exceptions:
  1576. X *    - to ease coding for ansi scrolls, the terminal is supposed to
  1577. X *    contain blanks at positions that were not written yet;
  1578. X *    the unknown rubbish that is initially on the screen can
  1579. X *    only be cleared by the caller by scrolling the whole screen up
  1580. X *    by one or more lines;
  1581. X *    - the number of lines on the terminal is assumed to be 25;
  1582. X *    the number of columns is (1) determined by a BIOS function, or
  1583. X *    (2) assumed to be 80 for ANSI;
  1584. X *    the user can overwrite this by setting the environment variable:
  1585. X *
  1586. X *        SET SCREEN=BIOS y x
  1587. X *    or
  1588. X *        SET SCREEN=ANSI y x
  1589. X *
  1590. X *    where x and y are the number of lines and columns respectively.
  1591. X *
  1592. X * The lines and columns of our virtual terminal are numbered
  1593. X *    y = {0...lines-1} from top to bottom, and
  1594. X *    x = {0...cols-1} from left to right,
  1595. X * respectively.
  1596. X *
  1597. X * The Visible Procedures in this package are as described in vtrm.c.
  1598. X *
  1599. X */
  1600. X
  1601. X/*
  1602. X * Includes and data definitions.
  1603. X */
  1604. X
  1605. X#include <stdio.h>
  1606. X#include <signal.h>
  1607. X#include <ctype.h>
  1608. X#include <dos.h>
  1609. X#include <fcntl.h>
  1610. X#include <io.h>
  1611. X
  1612. Xchar *malloc();
  1613. X
  1614. X#define STDIN_HANDLE 0
  1615. X
  1616. X#include "vtrm.h"
  1617. X
  1618. X#ifdef lint
  1619. X#define VOID (void)
  1620. X#else
  1621. X#define VOID
  1622. X#endif
  1623. X
  1624. X#define Forward
  1625. X#define Visible
  1626. X#define Hidden static
  1627. X#define Procedure
  1628. X
  1629. Xtypedef short intlet;
  1630. Xtypedef char *string;
  1631. Xtypedef char bool;
  1632. X#define Yes '\1'
  1633. X#define No  '\0'
  1634. X#define Undefined (-1)
  1635. X
  1636. X#define Min(a,b) ((a) <= (b) ? (a) : (b))
  1637. X
  1638. X#define MESS(number, text) text
  1639. X
  1640. X#ifdef GFX
  1641. X#include "gfx.h"
  1642. X#endif
  1643. X
  1644. X/* terminal status */
  1645. X
  1646. XHidden int started = No;
  1647. X
  1648. XHidden int scr_mode = 0;
  1649. X#define ANSI 'A'
  1650. X#define BIOS 'B'
  1651. X
  1652. X#define Nlines    25
  1653. X#define Ncols    80
  1654. XHidden int lines = Nlines;
  1655. XHidden int cols = Ncols;
  1656. XHidden int flags = 0;
  1657. X
  1658. X/* current standout mode */
  1659. X#define Off    0
  1660. X#define On    0200
  1661. XHidden int so_mode = Off;
  1662. X
  1663. X/* masks for char's and intlet's */
  1664. X#define NULCHAR '\000'
  1665. X#define CHAR    0177
  1666. X#define SOBIT    On
  1667. X#define SOCHAR    0377
  1668. X
  1669. X/* current cursor position */
  1670. XHidden intlet cur_y = Undefined, cur_x = Undefined;
  1671. X
  1672. X/* "line[y][x]" holds the char on the terminal, with the SOBIT.
  1673. X * the SOBIT tells whether the character is standing out.
  1674. X * "lenline[y]" holds the length of the line.
  1675. X * (Partially) empty lines are distinghuished by "lenline[y] < cols".
  1676. X * Unknown chars will be ' ', so the scrolling routines for ANSI
  1677. X * can use "unwritten" chars (with indent > 0 in trmputdata).
  1678. X * To make the optimising compare in putline fail, lenline[y] is initially 0.
  1679. X * The latter implies that if a line is first addressed with trmputdata,
  1680. X * any rubbish that is on the screen beyond the data that gets put, will
  1681. X * remain there.
  1682. X */
  1683. X
  1684. XHidden char **line = 0;
  1685. XHidden intlet *lenline = 0;
  1686. X
  1687. X/* Make the cursor invisible when trmsync() tries to move outside the screen */
  1688. XHidden bool no_cursor = No;
  1689. X
  1690. X/*
  1691. X * Starting, Ending and (fatal) Error.
  1692. X */
  1693. X
  1694. Xbool wasbreak;
  1695. X
  1696. X/*
  1697. X * Initialization call.
  1698. X * Determine terminal mode.
  1699. X * Start up terminal and internal administration.
  1700. X * Return Yes if succeeded, No if trouble (which doesn't apply here).
  1701. X */
  1702. X
  1703. XVisible int
  1704. Xtrmstart(plines, pcols, pflags)
  1705. Xint *plines;
  1706. Xint *pcols;
  1707. Xint *pflags;
  1708. X{
  1709. X    static char setup = No;
  1710. X    int err;
  1711. X
  1712. X#ifdef TRACE
  1713. Xif (!setup) freopen("TRACE.DAT", "a", stderr);
  1714. Xfprintf(stderr, "\ttrmstart(&li, &co, &fl);\n");
  1715. X#endif
  1716. X
  1717. X    if (started)
  1718. X        return TE_TWICE;
  1719. X
  1720. X#ifdef GFX
  1721. X    if (gfx_mode != TEXT_MODE)
  1722. X        gfx_mode= SPLIT_MODE;
  1723. X#endif
  1724. X
  1725. X    if (!setup) {
  1726. X        err= set_screen_up();
  1727. X        if (err != TE_OK)
  1728. X            return err;
  1729. X        setup = Yes;
  1730. X    }
  1731. X
  1732. X    err= start_trm();        /* internal administration */
  1733. X    if (err != TE_OK)
  1734. X        return err;
  1735. X
  1736. X    *plines = lines;
  1737. X    *pcols = cols;
  1738. X    *pflags = flags;
  1739. X
  1740. X    setmode(STDIN_HANDLE, O_BINARY); /* Don't translate CRLF to LF */
  1741. X    setraw(STDIN_HANDLE, Yes);
  1742. X    wasbreak= getbreak(); /* Save BREAK status; restore when done */
  1743. X    setbreak(No);
  1744. X
  1745. X    set_handler();
  1746. X    started = Yes;
  1747. X    return TE_OK;
  1748. X}
  1749. X
  1750. XHidden int
  1751. Xset_screen_up()
  1752. X{
  1753. X    int height;
  1754. X    int width;
  1755. X    int get_screen_env();
  1756. X    int get_cols();
  1757. X
  1758. X    height = width = 0;
  1759. X    scr_mode = get_screen_env(&height, &width);
  1760. X
  1761. X    switch (scr_mode) {
  1762. X    case BIOS:
  1763. X    case TE_OK:
  1764. X        cols = get_cols();
  1765. X        flags = HAS_STANDOUT|CAN_SCROLL;
  1766. X        break;
  1767. X    case ANSI:
  1768. X        flags = HAS_STANDOUT;
  1769. X        break;
  1770. X    default:
  1771. X        return scr_mode; /* Error flag */
  1772. X    }
  1773. X
  1774. X    /* allow x and y in environment variable SCREEN to override */
  1775. X    if (height > 0)
  1776. X        lines = height;
  1777. X    if (width > 0)
  1778. X        cols = width;
  1779. X    return TE_OK;
  1780. X}
  1781. X
  1782. XHidden int
  1783. Xget_screen_env(pheight, pwidth)
  1784. X    int *pheight, *pwidth;
  1785. X{
  1786. X    string s;
  1787. X    int mode;
  1788. X    char screrr;
  1789. X    string getenv();
  1790. X    string strip();
  1791. X    string skip();
  1792. X
  1793. X    screrr = No;
  1794. X    s = getenv("SCREEN");
  1795. X    if (s == NULL)
  1796. X        return BIOS;
  1797. X
  1798. X    s = strip(s);
  1799. X    switch (*s) {
  1800. X    case '\0':
  1801. X        return BIOS;
  1802. X    case 'a':
  1803. X        mode = ANSI;
  1804. X        s = skip(s, "ansi");
  1805. X        break;
  1806. X    case 'A':
  1807. X        mode = ANSI;
  1808. X        s = skip(s, "ANSI");
  1809. X        break;
  1810. X    case 'b':
  1811. X        mode = BIOS;
  1812. X        s = skip(s, "bios");
  1813. X        break;
  1814. X    case 'B':
  1815. X        mode = BIOS;
  1816. X        s = skip(s, "BIOS");
  1817. X        break;
  1818. X    default:
  1819. X        mode = BIOS;
  1820. X        screrr = Yes;
  1821. X    }
  1822. X
  1823. X    /* *pheight and *pwidth were set to 0 above */
  1824. X    s = strip(s);
  1825. X    while (isdigit(*s)) {
  1826. X        *pheight = *pheight * 10 + (*s++ - '0');
  1827. X    }
  1828. X    s = strip(s);
  1829. X    while (isdigit(*s)) {
  1830. X        *pwidth = *pwidth * 10 + (*s++ -'0');
  1831. X    }
  1832. X    s = strip(s);
  1833. X    if (screrr || *s != '\0')
  1834. X        return TE_BADTERM;
  1835. X
  1836. X    return mode;
  1837. X}
  1838. X
  1839. XHidden string strip(s)
  1840. Xstring s;
  1841. X{
  1842. X    while (*s == ' ' || *s == '\t')
  1843. X        ++s;
  1844. X    return s;
  1845. X}
  1846. X
  1847. XHidden string skip(s, pat)
  1848. Xstring s, pat;
  1849. X{
  1850. X    while (*s == *pat)
  1851. X        ++s, ++pat;
  1852. X    return s;
  1853. X}
  1854. X
  1855. XHidden int        /* initialise internal administration */
  1856. Xstart_trm()
  1857. X{
  1858. X    register int y;
  1859. X
  1860. X    if (line == 0) {
  1861. X        if ((line = (char**) malloc(lines * sizeof(char*))) == NULL)
  1862. X            return TE_NOMEM;
  1863. X        for (y = 0; y < lines; y++) {
  1864. X            if ((line[y] = malloc(cols * sizeof(char))) == NULL)
  1865. X                return TE_NOMEM;
  1866. X        }
  1867. X    }
  1868. X    if (lenline == 0) {
  1869. X        if ((lenline = (intlet *)
  1870. X                malloc(lines * sizeof(intlet))) == NULL)
  1871. X            return TE_NOMEM;
  1872. X    }
  1873. X
  1874. X    trmundefined();
  1875. X    return TE_OK;
  1876. X}
  1877. X
  1878. X/*
  1879. X * Termination call.
  1880. X * Beware that it might be called by a catched interrupt even in the middle
  1881. X * of trmstart()!
  1882. X */
  1883. X
  1884. XVisible Procedure
  1885. Xtrmend()
  1886. X{
  1887. X#ifdef TRACE
  1888. Xfprintf(stderr, "\ttrmend();\n");
  1889. X#endif
  1890. X    if (started && so_mode != Off)
  1891. X        standend();
  1892. X    if (scr_mode == ANSI) {
  1893. X        VOID fflush(stdout);
  1894. X    }
  1895. X    /* Always turn off RAW mode -- it is unlikely that anybody
  1896. X       would want to interface to COMMAND.COM in raw mode.
  1897. X       This way, if you were accidentally left in RAW mode
  1898. X       because of a crash, it will go away if you re-enter. */
  1899. X    setraw(STDIN_HANDLE, No);
  1900. X    setbreak(wasbreak);
  1901. X
  1902. X    started = No;
  1903. X}
  1904. X
  1905. X/*
  1906. X * Set all internal statuses to undefined, especially the contents of
  1907. X * the screen, so a hard redraw will not be optimised to heaven.
  1908. X */
  1909. X
  1910. XVisible Procedure
  1911. Xtrmundefined()
  1912. X{
  1913. X    register int y, x;
  1914. X#ifdef TRACE
  1915. Xfprintf(stderr, "\ttrmundefined();\n");
  1916. X#endif
  1917. X
  1918. X    cur_y = cur_x = Undefined;
  1919. X    so_mode = Undefined;
  1920. X
  1921. X    for (y = 0; y < lines; y++) {
  1922. X        for (x = 0; x < cols; x++)
  1923. X            line[y][x] = ' ';
  1924. X            /* they may get printed in scrolling */
  1925. X        lenline[y] = 0;
  1926. X    }
  1927. X}
  1928. X
  1929. X#ifdef DEBUG
  1930. XHidden Procedure
  1931. Xcheck_started(m)
  1932. X    char *m;
  1933. X{
  1934. X    if (!started) {
  1935. X        printf("Not started: %s\n", m);
  1936. X        exit(TE_TWICE);
  1937. X    }
  1938. X}
  1939. X#else
  1940. X#define check_started(m) /*empty*/
  1941. X#endif
  1942. X
  1943. X/*
  1944. X * Sensing the cursor.
  1945. X * (NOT IMPLEMENTED, since there is no way to locally move the cursor.)
  1946. X */
  1947. X
  1948. X/*
  1949. X * Sense the current (y, x) cursor position, after a possible manual
  1950. X * change by the user with local cursor motions.
  1951. X * If the terminal cannot be asked for the current cursor position,
  1952. X * or if the string returned by the terminal is garbled,
  1953. X * the position is made Undefined.
  1954. X */
  1955. XVisible Procedure
  1956. Xtrmsense(py, px)
  1957. X    int *py;
  1958. X    int *px;
  1959. X{
  1960. X/*    bool getpos(); */
  1961. X#ifdef TRACE
  1962. Xfprintf(stderr, "\ttrmsense(&yy, &xx);\n");
  1963. X#endif
  1964. X    check_started(MESS(7904, "trmsense called outside trmstart/trmend"));
  1965. X
  1966. X    *py = *px = Undefined;
  1967. X
  1968. X/*
  1969. X *    if (flags&CAN_SENSE && getpos(py, px)) {
  1970. X *        if (*py < 0 || lines <= *py || *px < 0 || cols <= *px)
  1971. X *            *py = *px = Undefined;
  1972. X *    }
  1973. X */
  1974. X    cur_y = *py;
  1975. X    cur_x = *px;
  1976. X}
  1977. X
  1978. X/*
  1979. X * Putting data on the screen.
  1980. X */
  1981. X
  1982. X/*
  1983. X * Fill screen area with given data.
  1984. X * Characters with the SO-bit (0200) set are put in standout mode.
  1985. X * (Unfortunately this makes it impossible to display accented characters.
  1986. X * The interface should change.)
  1987. X */
  1988. XVisible Procedure
  1989. Xtrmputdata(yfirst, ylast, indent, data)
  1990. Xint yfirst;
  1991. Xint ylast;
  1992. Xregister int indent;
  1993. Xregister string data;
  1994. X{
  1995. X    register int y;
  1996. X    int x, len, lendata, space;
  1997. X
  1998. X#ifdef TRACE
  1999. Xfprintf(stderr, "\ttrmputdata(%d, %d, %d, \"%s\");\n", yfirst, ylast, indent, data);
  2000. X#endif
  2001. X    check_started(MESS(7905, "trmputdata called outside trmstart/trmend"));
  2002. X
  2003. X    if (yfirst < 0)
  2004. X        yfirst = 0;
  2005. X    if (ylast >= lines)
  2006. X        ylast = lines-1;
  2007. X    space = cols*(ylast-yfirst+1) - indent;
  2008. X    if (space <= 0)
  2009. X        return;
  2010. X    yfirst += indent/cols;
  2011. X    indent %= cols;
  2012. X    y = yfirst;
  2013. X    if (data) {
  2014. X        x = indent;
  2015. X        lendata = strlen(data);
  2016. X        if (ylast == lines-1 && lendata >= space)
  2017. X            lendata = space - 1;
  2018. X        len = Min(lendata, cols-x);
  2019. X        while (len > 0 && y <= ylast) {
  2020. X            put_line(y, x, data, len);
  2021. X            y++;
  2022. X            lendata -= len;
  2023. X            if (lendata > 0) {
  2024. X                x = 0;
  2025. X                data += len;
  2026. X                len = Min(lendata, cols);
  2027. X            }
  2028. X            else
  2029. X                break;
  2030. X        }
  2031. X    }
  2032. X    if (y <= ylast)
  2033. X        clear_lines(y, ylast);
  2034. X}
  2035. X
  2036. X/*
  2037. X * We will try to get the picture:
  2038. X *
  2039. X *            op>>>>>>>>>>>op                       oq
  2040. X *            ^         ^                       ^
  2041. X *         <xskip><-----m1----><---------------od-------------------->
  2042. X *   OLD:   "You're in a maze of twisty little pieces of code, all alike"
  2043. X *   NEW:       "in a maze of little twisting pieces of code, all alike"
  2044. X *            <-----m1----><----------------nd--------------------->
  2045. X *            ^         ^                     ^
  2046. X *            np>>>>>>>>>>>np                     nq
  2047. X * where
  2048. X *    op, oq, np, nq are pointers to start and end of Old and New data,
  2049. X * and
  2050. X *    xskip = length of indent to be skipped,
  2051. X *    m1 = length of Matching part at start,
  2052. X *    od = length of Differing end on screen,
  2053. X *    nd = length of Differing end in data to be put.
  2054. X */
  2055. XHidden int
  2056. Xput_line(y, xskip, data, len)
  2057. Xint y, xskip;
  2058. Xstring data;
  2059. Xint len;
  2060. X{
  2061. X    register char *op, *oq, *np, *nq;
  2062. X    int m1, od, nd, delta;
  2063. X
  2064. X    /* calculate the magic parameters */
  2065. X    op = &line[y][xskip];
  2066. X    oq = &line[y][lenline[y]-1];
  2067. X    np = data;
  2068. X    nq = data + len - 1;
  2069. X    m1 = 0;
  2070. X    while ((*op&SOCHAR) == (*np&SOCHAR) && op <= oq && np <= nq)
  2071. X        op++, np++, m1++;
  2072. X    od = oq - op + 1;
  2073. X    nd = nq - np + 1;
  2074. X    /* now we have the picture above */
  2075. X
  2076. X    if (od==0 && nd==0)
  2077. X        return;
  2078. X
  2079. X    delta = nd - od;
  2080. X    move(y, xskip + m1);
  2081. X    if (nd > 0) {
  2082. X        put_str(np, nd);
  2083. X    }
  2084. X    if (delta < 0) {
  2085. X        clr_to_eol();
  2086. X        return;
  2087. X    }
  2088. X    lenline[y] = xskip + len;
  2089. X    if (cur_x == cols) {
  2090. X        cur_y++;
  2091. X        cur_x = 0;
  2092. X    }
  2093. X}
  2094. X
  2095. X/*
  2096. X * Scrolling (part of) the screen up (or down, dy<0).
  2097. X */
  2098. X
  2099. XVisible Procedure
  2100. Xtrmscrollup(yfirst, ylast, by)
  2101. Xregister int yfirst;
  2102. Xregister int ylast;
  2103. Xregister int by;
  2104. X{
  2105. X#ifdef TRACE
  2106. Xfprintf(stderr, "\ttrmscrollup(%d, %d, %d);\n", yfirst, ylast, by);
  2107. X#endif
  2108. X    check_started(MESS(7906, "trmscrollup called outside trmstart/trmend"));
  2109. X
  2110. X    if (by == 0)
  2111. X        return;
  2112. X
  2113. X    if (yfirst < 0)
  2114. X        yfirst = 0;
  2115. X    if (ylast >= lines)
  2116. X        ylast = lines-1;
  2117. X
  2118. X    if (yfirst > ylast)
  2119. X        return;
  2120. X
  2121. X    if (so_mode != Off)
  2122. X        standend();
  2123. X
  2124. X    if (by > 0 && yfirst + by > ylast
  2125. X        ||
  2126. X        by < 0 && yfirst - by > ylast)
  2127. X    {
  2128. X        clear_lines(yfirst, ylast);
  2129. X        return;
  2130. X    }
  2131. X
  2132. X    switch (scr_mode) {
  2133. X    case BIOS:
  2134. X        biosscrollup(yfirst, ylast, by);
  2135. X        break;
  2136. X    case ANSI:
  2137. X        if (by > 0 && yfirst == 0) {
  2138. X            lf_scroll(ylast, by);
  2139. X        }
  2140. X        else if (by > 0) {
  2141. X            move_lines(yfirst+by, yfirst, ylast-yfirst+1-by, 1);
  2142. X            clear_lines(ylast-by+1, ylast);
  2143. X        }
  2144. X        else {
  2145. X            move_lines(ylast+by, ylast, ylast-yfirst+1+by, -1);
  2146. X            clear_lines(yfirst, yfirst-by-1);
  2147. X        }
  2148. X        break;
  2149. X    }
  2150. X}
  2151. X
  2152. X/*
  2153. X * Synchronization, move cursor to given position (or previous if < 0).
  2154. X */
  2155. X
  2156. XVisible Procedure
  2157. Xtrmsync(y, x)
  2158. X    int y;
  2159. X    int x;
  2160. X{
  2161. X#ifdef TRACE
  2162. Xfprintf(stderr, "\ttrmsync(%d, %d);\n", y, x);
  2163. X#endif
  2164. X    check_started(MESS(7907, "trmsync called outside trmstart/trmend"));
  2165. X
  2166. X    if (0 <= y && y < lines && 0 <= x && x < cols) {
  2167. X        move(y, x);
  2168. X    }
  2169. X    VOID fflush(stdout);
  2170. X}
  2171. X
  2172. X/*
  2173. X * Send a bell, visible if possible.
  2174. X */
  2175. X
  2176. XVisible Procedure
  2177. Xtrmbell()
  2178. X{
  2179. X#ifdef TRACE
  2180. Xfprintf(stderr, "\ttrmbell();\n");
  2181. X#endif
  2182. X    check_started(MESS(7908, "trmbell called outside trmstart/trmend"));
  2183. X    ring_bell();
  2184. X}
  2185. X
  2186. X/*
  2187. X * Now for the real work: here are all low level routines that really
  2188. X * differ for BIOS or ANSI mode.
  2189. X */
  2190. X
  2191. X/*
  2192. X * BIOS video io is called by generating an 8086 software interrupt,
  2193. X * using lattice's int86() function.
  2194. X * To ease coding, all routines fill in the apropriate parameters in regs,
  2195. X * and then call bios10(code), where code is to be placed in ah.
  2196. X */
  2197. X
  2198. XHidden union REGS regs, outregs;
  2199. X
  2200. X/* A macro for speed  */
  2201. X#define bios10(code) (regs.h.ah = (code), int86(0x10, ®s, ®s))
  2202. X#define nbios10(code) (regs.h.ah = (code), int86(0x10, ®s, &outregs))
  2203. X
  2204. X/* Video attributes: (see the BASIC manual) (used for standout mode) */
  2205. X
  2206. XHidden int video_attr;
  2207. X#ifndef GFX
  2208. X#define V_NORMAL 7
  2209. X#else
  2210. X#define V_NORMAL (gfx_mode == TEXT_MODE ? 7 : 0)
  2211. X#endif
  2212. X#define V_STANDOUT (7<<4)
  2213. X
  2214. X/* Some BIOS only routines */
  2215. X
  2216. XHidden get_cols()
  2217. X{
  2218. X    bios10(15);
  2219. X    return regs.h.ah;
  2220. X}
  2221. X
  2222. X/*
  2223. X * ANSI escape sequences
  2224. X */
  2225. X#define A_CUP    "\033[%d;%dH"   /* cursor position */
  2226. X#define A_SGR0    "\033[0m"       /* set graphics rendition to normal */
  2227. X#define A_SGR7    "\033[7m"       /* set graphics rendition to standout */
  2228. X#define A_ED    "\033[2J"       /* erase display (and cursor home) */
  2229. X#define A_EL    "\033[K"        /* erase (to end of) line */
  2230. X
  2231. X/*
  2232. X * The following routine is the time bottleneck, I believe!
  2233. X */
  2234. X
  2235. XHidden Procedure
  2236. Xput_str(data, n)
  2237. Xchar *data;
  2238. Xint n;
  2239. X{
  2240. X    register char c, so;
  2241. X
  2242. X    so = so_mode;
  2243. X    if (scr_mode == BIOS) {
  2244. X        regs.x.cx = 1;    /* repition count */
  2245. X        regs.h.bh = 0;    /* page number */
  2246. X        regs.h.bl = video_attr;
  2247. X        while (--n >= 0) {
  2248. X            c = (*data++)&SOCHAR;
  2249. X            if ((c&SOBIT) != so) {
  2250. X                so = c&SOBIT;
  2251. X                so ? standout() : standend();
  2252. X                regs.h.bl = video_attr;
  2253. X            }
  2254. X            regs.h.al = c&CHAR;
  2255. X            nbios10(9);
  2256. X            if (cur_x >= cols-1) {
  2257. X                line[cur_y][cols-1] = c;
  2258. X                continue;
  2259. X            }
  2260. X            regs.h.dh = cur_y;
  2261. X            regs.h.dl = cur_x + 1;
  2262. X            nbios10(2);
  2263. X            line[cur_y][cur_x] = c;
  2264. X            cur_x++;
  2265. X        }
  2266. X    }
  2267. X    else {
  2268. X        while (--n >= 0) {
  2269. X            c = (*data++)&SOCHAR;
  2270. X            if ((c&SOBIT) != so) {
  2271. X                so = c&SOBIT;
  2272. X                so ? standout() : standend();
  2273. X            }
  2274. X            putch(c&CHAR);
  2275. X            line[cur_y][cur_x] = c;
  2276. X            cur_x++;
  2277. X        }
  2278. X    }
  2279. X}
  2280. X
  2281. X/*
  2282. X * Move to position y,x on the screen
  2283. X */
  2284. X
  2285. XHidden Procedure
  2286. Xmove(y, x)
  2287. Xint y, x;
  2288. X{
  2289. X    if (scr_mode != BIOS && cur_y == y && cur_x == x)
  2290. X        return;
  2291. X    switch (scr_mode) {
  2292. X    case BIOS:
  2293. X        regs.h.dh = y;
  2294. X        regs.h.dl = x;
  2295. X        regs.h.bh = 0; /* Page; must be 0 for graphics */
  2296. X        bios10(2);
  2297. X        break;
  2298. X    case ANSI:
  2299. X        cprintf(A_CUP, y+1, x+1);
  2300. X        break;
  2301. X    }
  2302. X    cur_y = y;
  2303. X    cur_x = x;
  2304. X}
  2305. X
  2306. XHidden Procedure
  2307. Xstandout()
  2308. X{
  2309. X    so_mode = On;
  2310. X    switch (scr_mode) {
  2311. X    case BIOS:
  2312. X        video_attr = V_STANDOUT;
  2313. X        break;
  2314. X    case ANSI:
  2315. X        cputs(A_SGR7);
  2316. X        break;
  2317. X    }
  2318. X}
  2319. X
  2320. XHidden Procedure
  2321. Xstandend()
  2322. X{
  2323. X    so_mode = Off;
  2324. X    switch (scr_mode) {
  2325. X    case BIOS:
  2326. X        video_attr = V_NORMAL;
  2327. X        break;
  2328. X    case ANSI:
  2329. X        cputs(A_SGR0);
  2330. X        break;
  2331. X    }
  2332. X}
  2333. X
  2334. X#ifdef UNUSED
  2335. XHidden Procedure
  2336. Xput_c(c)
  2337. Xint c;
  2338. X{
  2339. X    int ch;
  2340. X
  2341. X    ch = c&CHAR;
  2342. X#ifndef NDEBUG
  2343. X    if (!isprint(ch)) {
  2344. X        ch = '?';
  2345. X        c = (c&SOBIT)|'?';
  2346. X    }
  2347. X#endif
  2348. X    switch (scr_mode) {
  2349. X    case BIOS:
  2350. X        regs.h.al = ch;
  2351. X        regs.h.bl = video_attr;
  2352. X        regs.x.cx = 1;    /* repition count */
  2353. X        regs.h.bh = 0;    /* page number */
  2354. X        bios10(9);
  2355. X        if (cur_x >= cols-1) {
  2356. X            line[cur_y][cols-1] = c;
  2357. X            return;
  2358. X        }
  2359. X        regs.h.dh = cur_y;
  2360. X        regs.h.dl = cur_x + 1;
  2361. X        bios10(2);
  2362. X        break;
  2363. X    case ANSI:
  2364. X        putch(ch);
  2365. X        break;
  2366. X    }
  2367. X    line[cur_y][cur_x] = c;
  2368. X    cur_x++;
  2369. X}
  2370. X#endif /* UNUSED */
  2371. X
  2372. XHidden Procedure
  2373. Xclear_lines(yfirst, ylast)
  2374. Xint yfirst, ylast ;
  2375. X{
  2376. X    register int y;
  2377. X
  2378. X    if (scr_mode == BIOS) {
  2379. X        regs.h.al = 0;    /* scroll with al = 0 means blank window */
  2380. X        regs.h.ch = yfirst;
  2381. X        regs.h.cl = 0;
  2382. X        regs.h.dh = ylast;
  2383. X        regs.h.dl = cols-1;
  2384. X        regs.h.bh = V_NORMAL;
  2385. X        bios10(6);
  2386. X        for (y = yfirst; y <= ylast; y++)
  2387. X            lenline[y] = 0;
  2388. X        return;
  2389. X    }
  2390. X    /* scr_mode == ANSI */
  2391. X    if (yfirst == 0 && ylast == lines-1) {
  2392. X        if (so_mode == On)
  2393. X            standend();
  2394. X        move(0, 0);        /* since some ANSI'd don't move */
  2395. X        cputs(A_ED);
  2396. X        cur_y = cur_x = 0;
  2397. X        for (y = yfirst; y < ylast; y++)
  2398. X            lenline[y] = 0;
  2399. X        return;
  2400. X    }
  2401. X    for (y = yfirst; y <= ylast; y++) {
  2402. X        if (lenline[y] > 0) {
  2403. X            move(y, 0);
  2404. X            clr_to_eol();
  2405. X        }
  2406. X    }
  2407. X}
  2408. X
  2409. XHidden Procedure
  2410. Xclr_to_eol()
  2411. X{
  2412. X    if (so_mode == On)
  2413. X        standend();
  2414. X    switch (scr_mode) {
  2415. X    case BIOS:
  2416. X        regs.h.bh = 0;    /* page */
  2417. X        regs.x.cx = lenline[cur_y] - cur_x;
  2418. X        regs.h.al = ' ';
  2419. X        regs.h.bl = V_NORMAL;
  2420. X        bios10(9);
  2421. X        break;
  2422. X    case ANSI:
  2423. X        cputs(A_EL);
  2424. X        break;
  2425. X    }
  2426. X    lenline[cur_y] = cur_x;
  2427. X}
  2428. X
  2429. XHidden Procedure        /* scrolling for BIOS */
  2430. Xbiosscrollup(yfirst, ylast, by)
  2431. Xint yfirst;
  2432. Xint ylast;
  2433. Xint by;
  2434. X{
  2435. X    regs.h.al = (by < 0 ? -by : by);
  2436. X    regs.h.ch = yfirst;
  2437. X    regs.h.cl = 0;
  2438. X    regs.h.dh = ylast;
  2439. X    regs.h.dl = cols-1;
  2440. X    regs.h.bh= V_NORMAL;
  2441. X    bios10(by < 0 ? 7 : 6);
  2442. X    cur_y = cur_x = Undefined;
  2443. X    if (by > 0)
  2444. X        scr_lines(yfirst, ylast, by, 1);
  2445. X    else
  2446. X        scr_lines(ylast, yfirst, -by, -1);
  2447. X}
  2448. X
  2449. XHidden Procedure        /* Reset internal administration accordingly */
  2450. Xscr_lines(yfrom, yto, n, dy)
  2451. Xint yfrom, yto, n, dy;
  2452. X{
  2453. X    register int y, x;
  2454. X    char *saveln;
  2455. X
  2456. X    while (n-- > 0) {
  2457. X        saveln = line[yfrom];
  2458. X        for (y = yfrom; y != yto; y += dy) {
  2459. X            line[y] = line[y+dy];
  2460. X            lenline[y] = lenline[y+dy];
  2461. X        }
  2462. X        line[yto] = saveln;
  2463. X        for (x = 0; x < cols; x++ )
  2464. X            line[yto][x] = ' ';
  2465. X        lenline[yto] = 0;
  2466. X    }
  2467. X}
  2468. X
  2469. XHidden Procedure
  2470. Xlf_scroll(yto, by)
  2471. Xint yto;
  2472. Xint by;
  2473. X{
  2474. X    register int n = by;
  2475. X
  2476. X    move(lines-1, 0);
  2477. X    while (n-- > 0) {
  2478. X        putch('\n');
  2479. X    }
  2480. X    scr_lines(0, lines-1, by, 1);
  2481. X    move_lines(lines-1-by, lines-1, lines-1-yto, -1);
  2482. X    clear_lines(yto-by+1, yto);
  2483. X}
  2484. X
  2485. XHidden Procedure        /* for dumb scrolling, uses and updates */
  2486. Xmove_lines(yfrom, yto, n, dy)    /* internal administration */
  2487. Xint yfrom;
  2488. Xint yto;
  2489. Xint n;
  2490. Xint dy;
  2491. X{
  2492. X    while (n-- > 0) {
  2493. X        put_line(yto, 0, line[yfrom], lenline[yfrom]);
  2494. X        yfrom += dy;
  2495. X        yto += dy;
  2496. X    }
  2497. X}
  2498. X
  2499. XHidden Procedure ring_bell()
  2500. X{
  2501. X    switch (scr_mode) {
  2502. X    case BIOS:
  2503. X        regs.h.al = '\007';
  2504. X        regs.h.bl = V_NORMAL;
  2505. X        bios10(14);
  2506. X        break;
  2507. X    case ANSI:
  2508. X        putch('\007');
  2509. X        break;
  2510. X    }
  2511. X}
  2512. X
  2513. X/*
  2514. X * Show the current internal statuses of the screen on stderr.
  2515. X * For debugging only.
  2516. X */
  2517. X
  2518. X#ifdef SHOW
  2519. XVisible Procedure
  2520. Xtrmshow(s)
  2521. Xchar *s;
  2522. X{
  2523. X    int y, x;
  2524. X
  2525. X    fprintf(stderr, "<<< %s >>>\n", s);
  2526. X    for (y = 0; y < lines; y++) {
  2527. X        for (x = 0; x <= lenline[y] /*** && x < cols ***/ ; x++) {
  2528. X            fputc(line[y][x]&CHAR, stderr);
  2529. X        }
  2530. X        fputc('\n', stderr);
  2531. X        for (x = 0; x <= lenline[y] && x < cols-1; x++) {
  2532. X            if (line[y][x]&SOBIT)
  2533. X                fputc('-', stderr);
  2534. X            else
  2535. X                fputc(' ', stderr);
  2536. X        }
  2537. X        fputc('\n', stderr);
  2538. X    }
  2539. X    fprintf(stderr, "CUR_Y = %d, CUR_X = %d.\n", cur_y, cur_x);
  2540. X    VOID fflush(stderr);
  2541. X}
  2542. X#endif
  2543. X
  2544. X/*
  2545. X * Interrupt handling.
  2546. X *
  2547. X * (This has not properly been tested, nor is it clear that
  2548. X * this interface is what we want.  Anyway, it's here for you
  2549. X * to experiment with.  What does it do, you may ask?
  2550. X * Assume an interactive program which reads its characters
  2551. X * through trminput.  Assume ^C is the interrupt character.
  2552. X * Normally, ^C is treated just like any other character: when
  2553. X * typed, it turns up in the input.  The program may understand
  2554. X * input ^C as "quit from the current mode".
  2555. X * Occasionally, the program goes into a long period of computation.
  2556. X * Now it would be uninterruptible, except if it calls trminterrupt
  2557. X * at times in its computational loop.  Trminterrupt magically looks
  2558. X * ahead in the input queue, and if it sees a ^C, discards all input
  2559. X * before that point and returns Yes.  It also sets a flag, so that
  2560. X * the interupt "sticks around" until either trminput or trmavail
  2561. X * is called.  It is undefined whether typing ^C several times in
  2562. X * a row is seen as one interrupt, or an interrupt followed by input
  2563. X * of ^C's.  A program should be prepared for either.)
  2564. X */
  2565. X
  2566. Xstatic bool intrflag= No;
  2567. X
  2568. Xstatic
  2569. Xhandler(sig)
  2570. X    int sig;
  2571. X{
  2572. X    signal(sig, handler);
  2573. X    intrflag= Yes;
  2574. X}
  2575. X
  2576. Xstatic
  2577. Xset_handler()
  2578. X{
  2579. X    signal(SIGINT, handler);
  2580. X}
  2581. X
  2582. Xbool
  2583. Xtrminterrupt()
  2584. X{
  2585. X    /* Force a check for ^C which will call handler. */
  2586. X    /* (This does a ^C check even if stdin is in RAW mode. */
  2587. X    (void) kbhit();
  2588. X    return intrflag;
  2589. X}
  2590. X
  2591. X
  2592. X/* Definitions for DOS function calls. */
  2593. X
  2594. X#define IOCTL        0x44
  2595. X#define IOCTL_GETDATA    0x4400
  2596. X#define IOCTL_SETDATA    0x4401
  2597. X#define DEVICEBIT    0x80
  2598. X#define RAWBIT        0x20
  2599. X
  2600. X#define BREAKCK        0x33
  2601. X#define GET        0x00
  2602. X#define SET        0x01
  2603. X
  2604. X#define IOCTL_GETSTS    0x4406
  2605. X
  2606. X#define STDIN_HANDLE    0
  2607. X
  2608. X/*
  2609. X * Terminal input without echo.
  2610. X */
  2611. X
  2612. Xint
  2613. Xtrminput()
  2614. X{
  2615. X    char c;
  2616. X    
  2617. X    intrflag= No;
  2618. X    /* Assume stdin is in RAW mode; this turns echo and ^C checks off. */
  2619. X    if (read(STDIN_HANDLE, &c, 1) < 1)
  2620. X        return -1;
  2621. X    else
  2622. X        return c;
  2623. X}
  2624. X
  2625. X/*
  2626. X * Check for character available.
  2627. X *
  2628. X */
  2629. X
  2630. Xtrmavail()
  2631. X{
  2632. X    intrflag= No;
  2633. X    regs.x.ax= IOCTL_GETSTS;
  2634. X    regs.x.bx= STDIN_HANDLE;
  2635. X    intdos(®s, ®s);
  2636. X    if (regs.x.cflag)
  2637. X        return -1; /* Error */
  2638. X    return regs.h.al != 0;
  2639. X}
  2640. X
  2641. Xtrmsuspend()
  2642. X{
  2643. X    /* Not implementable on MS-DOS */
  2644. X}
  2645. X
  2646. X/* Issue an IOCTL to turn RAW for a device on or off. */
  2647. X
  2648. Xsetraw(handle, raw)
  2649. X    int handle;
  2650. X    bool raw;
  2651. X{
  2652. X    regs.x.ax= IOCTL_GETDATA;
  2653. X    regs.x.bx= handle;
  2654. X    intdos(®s, ®s);
  2655. X    if (regs.x.cflag || !(regs.h.dl & DEVICEBIT))
  2656. X        return; /* Error or not a device -- ignore it */
  2657. X    regs.h.dh= 0;
  2658. X    if (raw)
  2659. X        regs.h.dl |= RAWBIT;
  2660. X    else
  2661. X        regs.h.dl &= ~RAWBIT;
  2662. X    regs.x.ax= IOCTL_SETDATA;
  2663. X    intdos(®s, ®s);
  2664. X    /* Ignore errors */
  2665. X}
  2666. X
  2667. X/* Get the raw bit of a device. */
  2668. X
  2669. Xint
  2670. Xgetraw(handle)
  2671. X    int handle;
  2672. X{
  2673. X    regs.x.ax= IOCTL_GETDATA;
  2674. X    regs.x.bx= handle;
  2675. X    intdos(®s, ®s);
  2676. X    return !regs.x.cflag &&
  2677. X        (regs.h.dh & (DEVICEBIT|RAWBIT)) == (DEVICEBIT|RAWBIT);
  2678. X}
  2679. X
  2680. X/* Set the break status. */
  2681. X
  2682. Xsetbreak(on)
  2683. X    bool on;
  2684. X{
  2685. X    bdos(BREAKCK, on, SET);
  2686. X}
  2687. X
  2688. X/* Get the break status. */
  2689. X
  2690. Xint
  2691. Xgetbreak()
  2692. X{
  2693. X    regs.x.ax= (BREAKCK << 8) | GET;
  2694. X    intdos(®s, ®s);
  2695. X    return regs.h.dl;
  2696. X}
  2697. END_OF_FILE
  2698. if test 23047 -ne `wc -c <'Ports/msdos/ptrm.c'`; then
  2699.     echo shar: \"'Ports/msdos/ptrm.c'\" unpacked with wrong size!
  2700. fi
  2701. # end of 'Ports/msdos/ptrm.c'
  2702. fi
  2703. echo shar: End of archive 5 \(of 19\).
  2704. cp /dev/null ark5isdone
  2705. MISSING=""
  2706. for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 ; do
  2707.     if test ! -f ark${I}isdone ; then
  2708.     MISSING="${MISSING} ${I}"
  2709.     fi
  2710. done
  2711. if test "${MISSING}" = "" ; then
  2712.     echo You have unpacked all 19 archives.
  2713.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  2714. else
  2715.     echo You still need to unpack the following archives:
  2716.     echo "        " ${MISSING}
  2717. fi
  2718. ##  End of shell archive.
  2719. exit 0
  2720.