home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / sun / volume1 / contool2.1 / contool.c next >
Encoding:
C/C++ Source or Header  |  1989-06-21  |  21.2 KB  |  733 lines

  1. /************************************************************************/
  2. /*    Copyright 1988 by Chuck Musciano and Harris Corporation        */
  3. /*                                    */
  4. /*    Permission to use, copy, modify, and distribute this software    */
  5. /*    and its documentation for any purpose and without fee is    */
  6. /*    hereby granted, provided that the above copyright notice    */
  7. /*    appear in all copies and that both that copyright notice and    */
  8. /*    this permission notice appear in supporting documentation, and    */
  9. /*    that the name of Chuck Musciano and Harris Corporation not be    */
  10. /*    used in advertising or publicity pertaining to distribution    */
  11. /*    of the software without specific, written prior permission.    */
  12. /*    Chuck Musciano and Harris Corporation make no representations    */
  13. /*    about the suitability of this software for any purpose.  It is    */
  14. /*    provided "as is" without express or implied warranty.        */
  15. /************************************************************************/
  16.  
  17.  
  18. /************************************************************************/
  19. /*                                    */
  20. /*    contool:    capture and display timestamped console i/o    */
  21. /*                                    */
  22. /************************************************************************/
  23.  
  24. #include    <stdio.h>
  25. #include    <fcntl.h>
  26. #include    <sys/ioctl.h>
  27. #include    <sys/types.h>
  28. #include    <sys/stat.h>
  29.  
  30. #include    <suntool/sunview.h>
  31. #include    <suntool/textsw.h>
  32. #include    <suntool/icon_load.h>
  33.  
  34. /**************** Site dependent parameters ****************************/
  35.  
  36. /* Where the default contool icons are kept.  !Must end in '/'! */
  37.  
  38. #if !defined(ICON_DIRECTORY)
  39. #define        ICON_DIRECTORY        "./icons/"
  40. #endif
  41.  
  42. /* The default icon names.  Alternate sets are shown, and you might want
  43.    to try these instead of the default set by uncommenting the desired set. */
  44.  
  45. /* This set gives a blinking stop sign when messages arrive. */
  46. #define        GOOD_ICON        "contool.icon"
  47. #define        BAD_ICON        "stopsign.icon"
  48. #define        INVERSE_ICON        "stopsign_inv.icon"
  49.  
  50. /* This set gives a terminal, labelled "Console", in a box.  The screen
  51.    flashes when messages arrive. */
  52. /* #define        GOOD_ICON    "contool.icon" */
  53. /* #define        BAD_ICON    "contool.icon" */
  54. /* #define        INVERSE_ICON    "contool_bad.icon" */
  55.  
  56. /* This set gives a terminal, without a box.  Again, the screen flashes
  57.    when messages arrive. */
  58. /* #define        GOOD_ICON    "console1.icon" */
  59. /* #define        BAD_ICON    "console1_bad.icon" */
  60. /* #define        INVERSE_ICON    "console1_flash.icon" */
  61.  
  62. /*************** End of site dependencies ******************************/
  63.  
  64. #define        TOOL_LABEL        "<< Console Tool 2.1 >>"
  65.  
  66. #define        MAX_FILTERS        64
  67.  
  68. #define        strsave(s)        ((char *) strcpy(malloc(strlen(s) + 1), s))
  69.  
  70. #define        BEEP_COUNT        3
  71. #define        TS_INTERVAL        60
  72.  
  73. #define        NORMAL_MODE        1
  74. #define        QUIET_MODE        2
  75. #define        IGNORE_MODE        3
  76.  
  77. #define        TEXT_SIZE_LIMIT        32768
  78. #define        TEXT_SIZE_FUZZ        1024
  79. #define        TEXT_DELETE_SIZE    1024
  80.  
  81. #define        INPUT_BUFFER_SIZE    4096
  82.  
  83. /*************** Stuff that regexp(3) needs ****************************/
  84.  
  85. static    regexp_error();
  86.  
  87. #define        INIT            register char *expbuf = ep, *sp = instring;
  88. #define        GETC()            (*sp++)
  89. #define        PEEKC()            (*sp)
  90. #define        UNGETC(c)        (--sp)
  91. #define        RETURN(p)        {bcopy(expbuf, sp = (char *) malloc(p - expbuf), p - expbuf); return(sp);}
  92. #define        ERROR(val)        {regexp_error(val, instring); return(NULL);}
  93.  
  94. #include    <regexp.h>
  95.  
  96. /*************** Things that contool uses ******************************/
  97.  
  98. struct    f_rec    {char    *start;
  99.          char    *end;
  100.          int    scircf;
  101.          int    ecircf;
  102.          int    mode;
  103.         };
  104.  
  105. char    *ct_usage = "usage: contool [-b <file>] [-c <file>] [-d <size>] [-f <file>] [-g <file>] [-l <size>] [-o <logfile>] [-p] [-r <amt>] [-s <amt>]\n";
  106.  
  107. static    Frame    bf;
  108. static    Textsw    text;
  109. static    Icon    good, bad, inverse;
  110. static    struct    pixrect    *good_pr, *bad_pr, *inv_pr;
  111. static    Menu_item    stop_blink;
  112. static    Rect    open_rect;
  113.  
  114. static    char    bad_icon[256];            /* -b */
  115. static    char    filter_path[256];        /* -c */
  116. static    int    delete_amt = TEXT_DELETE_SIZE;    /* -d */
  117. static    char    inv_icon[256];            /* -f */
  118. static    char    good_icon[256];            /* -g */
  119. static    int    size_limit = TEXT_SIZE_LIMIT;    /* -l */
  120. static    int    pop_open = FALSE;        /* -p */
  121. static    int    resolution = TS_INTERVAL;    /* -r */
  122. static    int    beep_amount = BEEP_COUNT;    /* -s */
  123.  
  124. static    int    bad_is_up;
  125. static    int    beep_count;
  126. static    int    blinking = FALSE;
  127. static    int    event_in_progress = FALSE;
  128. static    int    explicit_filters = FALSE;
  129. static    struct    f_rec    filter[MAX_FILTERS];
  130. static    int    filters = 0;
  131. static    int    icon_height;
  132. static    int    icon_width;
  133. static    FILE    *master = NULL;
  134. static    int    old_time = 0;
  135. static    char    *program;
  136. static    FILE    *slave = NULL;
  137. static  FILE    *logfile = NULL;
  138.  
  139. static    struct    itimerval    timer = {{0, 500000}, {0, 500000}};
  140.  
  141. /************************************************************************/
  142. /*    First, some basic console utility routines             */
  143. /************************************************************************/
  144.  
  145. /************************************************************************/
  146. static    acquire_console(path)
  147.  
  148. char    *path;
  149.  
  150. {
  151.     if (ioctl(fileno(slave), TIOCCONS, NULL) == -1) {
  152.        fprintf(stderr, "%s: could not attach %s to /dev/console\n", program, path);
  153.        exit(1);
  154.        }
  155. }
  156.  
  157. /************************************************************************/
  158. static    clear_messages()
  159.  
  160. {
  161.     textsw_reset(text, 0, 0);
  162.     old_time = 0;
  163. }
  164.  
  165. /************************************************************************/
  166. static    stop_blinking()
  167.  
  168. {
  169.     notify_set_itimer_func(bf, NULL, ITIMER_REAL, NULL, NULL);
  170.     window_set(bf, FRAME_ICON, good, 0);
  171.     blinking = FALSE;
  172.     menu_set(stop_blink, MENU_INACTIVE, TRUE, 0);
  173. }
  174.  
  175. /************************************************************************/
  176. /*    Now, filter and regular expression handlers            */
  177. /************************************************************************/
  178.  
  179. /************************************************************************/
  180. static    internal_message(a, b, c, d, e, f)
  181.  
  182. int    a, b, c, d, e, f;
  183.  
  184. {    char    buf[512];
  185.  
  186.     sprintf(buf, a, b, c, d, e, f);
  187.     time_stamp();
  188.     write_log(buf);
  189.     do_insertion(buf, strlen(buf));
  190. }
  191.  
  192. /************************************************************************/
  193. static    internal_error(a, b, c, d, e, f)
  194.  
  195. int    a, b, c, d, e, f;
  196.  
  197. {    char    buf[512];
  198.  
  199.     sprintf(buf, a, b, c, d, e, f);
  200.     time_stamp();
  201.     fprintf(stderr, buf);
  202. }
  203.  
  204. /************************************************************************/
  205. static    int    match_exp(exp, circ, str)
  206.  
  207. char    *exp;
  208. int    circ;
  209. char    *str;
  210.  
  211. {
  212.     circf = circ;
  213.     return(step(str, exp));
  214. }
  215.  
  216. /************************************************************************/
  217. static    regexp_error(val, string)
  218.  
  219. int    val;
  220. char    *string;
  221.  
  222. {    char    *msg;
  223.  
  224.     switch (val) {
  225.        case 11 : msg = "range endpoint too large";
  226.        case 16 : msg = "bad number";
  227.        case 25 : msg = "\"\\digit\" out of range";
  228.        case 36 : msg = "illegal or missing delimiter";
  229.        case 41 : msg = "no remembered search string";
  230.        case 42 : msg = "\\(\\) imbalance";
  231.        case 43 : msg = "too many \\(";
  232.        case 44 : msg = "more than 2 numbers given in \\{\\}";
  233.        case 45 : msg = "} expected after \\";
  234.        case 46 : msg = "first number exceeds second in \\{\\}";
  235.        case 49 : msg = "[] imbalance";
  236.        case 50 : msg = "regular expression overflow";
  237.        default : msg = "regular expression compilation error";
  238.        }
  239.     internal_error("*** %s: %s in '%s'\n", program, msg, string);
  240. }
  241.  
  242. /************************************************************************/
  243. static    load_filters()
  244.  
  245. {    FILE    *f;
  246.     char    buf[256], rbuf[1024], *token[6], *p, *index();
  247.     int    count;
  248.     struct    stat    sb;
  249.     static    int    load_time = 0;
  250.  
  251.     if (stat(filter_path, &sb) == -1) {
  252.        if (explicit_filters && load_time == 0) {
  253.           internal_error("*** %s: filter file %s cannot be accessed\n", program, filter_path);
  254.           load_time = 1;
  255.           }
  256.        return;
  257.        }
  258.     if (sb.st_mtime > load_time) {
  259.        for (count = 0; count < filters; count++) {
  260.           free(filter[count].start);
  261.           if (filter[count].end)
  262.              free(filter[count].end);
  263.           }
  264.        filters = 0;
  265.        }
  266.     else
  267.        return;
  268.  
  269.     if ((f = fopen(filter_path, "r")) != NULL) {
  270.        while (getline(f, buf, 256) != EOF) {
  271.           if ((p = index(buf, '#')) != NULL)
  272.              *p = '\0';
  273.           if (strlen(buf) == 0 || verify(buf, " "))
  274.              continue;
  275.           tokenize(buf, &count, token, 6);
  276.           if (count == 2 || count == 4) {
  277.              if (strcmp(lower(token[0]), "ignore") == 0)
  278.                 filter[filters].mode = IGNORE_MODE;
  279.              else if (strcmp(token[0], "quiet") == 0)
  280.                 filter[filters].mode = QUIET_MODE;
  281.              else {
  282.                 internal_error("*** %s: invalid contool filter:\n***\t%s\n", program, buf);
  283.                 continue;
  284.                 }
  285.              if ((filter[filters].start = compile(token[1], rbuf, rbuf+1024, '\0')) == NULL)
  286.                 continue;
  287.              filter[filters].scircf = circf;
  288.              if (count == 4)
  289.                 if (strcmp(lower(token[2]), "to") == 0) {
  290.                    filter[filters].end = compile(token[3], rbuf, rbuf+1024, '\0');
  291.                    filter[filters].ecircf = circf;
  292.                    }
  293.                 else {
  294.                    internal_error("*** %s: invalid contool filter:\n***\t%s\n", program, buf);
  295.                    continue;
  296.                    }
  297.              else
  298.                 filter[filters].end = NULL;
  299.              filters++;
  300.              }
  301.           else
  302.              internal_error("*** %s: invalid contool filter:\n\t%s\n", program, buf);
  303.           }
  304.        fclose(f);
  305.        internal_message("*** filters loaded from %s\n", filter_path);
  306.        load_time = sb.st_mtime;
  307.        }
  308.     else
  309.        internal_error("*** %s: could not read filter file %s\n", program, filter_path);
  310. }
  311.  
  312. /************************************************************************/
  313. /*    Various event handlers for the console frame            */
  314. /************************************************************************/
  315.  
  316. /************************************************************************/
  317. static    Notify_value    blink_proc(me, which)
  318.  
  319. int    *me;
  320. int    which;
  321.  
  322. {
  323.     if (event_in_progress)
  324.        return(NOTIFY_DONE);
  325.     if (beep_count > 0) {
  326.        window_bell(bf);
  327.        beep_count--;
  328.        }
  329.     else if (blinking) {
  330.        if (bad_is_up)
  331.           window_set(bf, FRAME_ICON, inverse, 0);
  332.        else
  333.           window_set(bf, FRAME_ICON, bad, 0);
  334.        bad_is_up = !bad_is_up;
  335.        }
  336.     if (beep_count == 0 && !blinking)
  337.        notify_set_itimer_func(bf, blink_proc, ITIMER_REAL, NULL, NULL);
  338.     return(NOTIFY_DONE);
  339. }
  340.  
  341. /************************************************************************/
  342. static    Notify_value    close_proc(frame, event, arg, type)
  343.  
  344. Frame    frame;
  345. Event    *event;
  346. Notify_arg    arg;
  347. Notify_event_type    type;
  348.  
  349. {    int    init_closed, curr_closed, is_resize;
  350.     Notify_value    value;
  351.     Rect    *temp;
  352.  
  353.     event_in_progress = TRUE;
  354.     init_closed = (int) window_get(frame, FRAME_CLOSED);
  355.     is_resize = (event_id(event) == WIN_RESIZE);
  356.     value = notify_next_event_func(frame, event, arg, type);
  357.     curr_closed = (int) window_get(frame, FRAME_CLOSED);
  358.     if (init_closed != curr_closed)
  359.        if (!curr_closed && blinking) {
  360.           notify_set_itimer_func(bf, blink_proc, ITIMER_REAL, NULL, NULL);
  361.           window_set(bf, FRAME_ICON, good, 0);
  362.           blinking = FALSE;
  363.           menu_set(stop_blink, MENU_INACTIVE, TRUE, 0);
  364.           }
  365.     event_in_progress = FALSE;
  366.     if (is_resize) {
  367.        temp = (Rect *) window_get(frame, FRAME_OPEN_RECT);
  368.        if (temp->r_width <= icon_width && temp->r_height <= icon_height) { /* override spurious resize request */
  369.           window_set(frame, FRAME_OPEN_RECT, &open_rect, FRAME_CLOSED, FALSE, 0);
  370.           notify_set_itimer_func(bf, blink_proc, ITIMER_REAL, NULL, NULL);
  371.           window_set(bf, FRAME_ICON, good, 0);
  372.           blinking = FALSE;
  373.           menu_set(stop_blink, MENU_INACTIVE, TRUE, 0);
  374.           }
  375.        else /* save away new open rect */
  376.           open_rect = *temp;
  377.        }
  378.     return(value);
  379. }
  380.  
  381. /************************************************************************/
  382. static    Notify_value    destroy_proc(frame, status)
  383.  
  384. Frame    frame;
  385. Destroy_status    status;
  386.  
  387. {
  388.     if (status == DESTROY_CHECKING) {
  389.        textsw_reset(text, 0, 0);
  390.        return(NOTIFY_DONE);
  391.        }
  392.     else
  393.        return(notify_next_destroy_func(frame, status));
  394. }
  395.  
  396. /************************************************************************/
  397. /*    Routines which handle capturing and displaying messages        */
  398. /************************************************************************/
  399.  
  400. /************************************************************************/
  401. static    write_log(s)
  402.  
  403. char    *s;
  404.  
  405. {    int    t;
  406.     static    char    hostname[100] = "";
  407.  
  408.     if (logfile) {
  409.        if (*hostname == NULL) 
  410.           if (gethostname(hostname, 99) != 0)
  411.              strcpy(hostname, "(unknown)");
  412.        t = time(0);
  413.        fseek(logfile, 0L, 2);
  414.        fprintf(logfile, "%s\t%.16s\t%s", hostname, ctime(&t) + 4, s);
  415.        fflush(logfile);
  416.        }
  417. }
  418.  
  419. /************************************************************************/
  420. static    do_insertion(buf, len)
  421.  
  422. char    *buf;
  423. int    len;
  424.  
  425. {    int    first, last;
  426.  
  427.     while (len > size_limit - ((int) window_get(text, TEXTSW_LENGTH) - TEXT_SIZE_FUZZ)) { /* make some room */
  428.        first = 1;
  429.        last = TEXTSW_INFINITY;
  430.        if (textsw_find_bytes(text, &first, &last, "\n<<<", 4, 0) == -1)
  431.           if (textsw_find_bytes(text, &first, &last, "\n", 1, 0) == -1)
  432.              first = delete_amt;
  433.        textsw_delete(text, 0, first + 1);
  434.        }
  435.     window_set(text, TEXTSW_INSERTION_POINT, TEXTSW_INFINITY, 0);
  436.     textsw_insert(text, buf, len);
  437. }
  438.  
  439. /************************************************************************/
  440. static    time_stamp()
  441.  
  442. {    int    t, pos;
  443.     char    buf[5];
  444.  
  445.     t = time(0);
  446.     if (t - old_time >= resolution) {
  447.        window_set(text, TEXTSW_INSERTION_POINT, TEXTSW_INFINITY, 0);
  448.        pos = (int) window_get(text, TEXTSW_LENGTH);
  449.        if (pos != 0) {
  450.           window_get(text, TEXTSW_CONTENTS, pos - 1, buf, 1);
  451.           if (buf[0] != '\n')
  452.              do_insertion("\n", 1);
  453.           }
  454.        do_insertion("\n<<< ", 5);
  455.        do_insertion(ctime(&t), 24);
  456.        do_insertion(" >>>\n", 5);
  457.        old_time = t;
  458.        }
  459. }
  460.  
  461. /************************************************************************/
  462. static    Notify_value    input_func(me, fd)
  463.  
  464. int    *me;
  465. int    fd;
  466.  
  467. {    char    old_c, *s, *t, *index();
  468.     int    i, count, do_blink = FALSE;
  469.     static    int    curr_filter = -1, curr_mode = NORMAL_MODE;
  470.     static    char    in_buf[INPUT_BUFFER_SIZE + 2];
  471.  
  472.     while ((count = read(fileno(master), in_buf, INPUT_BUFFER_SIZE)) >= 0) {
  473.        in_buf[count] = '\0';
  474.        while (s = index(in_buf, '\015')) {
  475.           strcpy(s, s + 1);
  476.           count--;
  477.           }
  478.        for (t = in_buf; *t; *s = old_c, t = s) {
  479.           if (s = index(t, '\n')) {
  480.              old_c = *++s;
  481.              *s = '\0';
  482.              }
  483.           else {
  484.              s = t + strlen(t);
  485.              old_c = '\0';
  486.              }
  487.           if (curr_mode == NORMAL_MODE) {
  488.              load_filters();
  489.              for (i = 0; i < filters; i++)
  490.                 if (match_exp(filter[i].start, filter[i].scircf, t)) {
  491.                    if (filter[i].mode == QUIET_MODE) {
  492.                       time_stamp();
  493.               write_log(t);
  494.                       do_insertion(t, strlen(t));
  495.                       }
  496.                    if (filter[i].end) {
  497.                       curr_mode = filter[i].mode;
  498.                       curr_filter = i;
  499.                       }
  500.                    break;
  501.                    }
  502.              if (i == filters) {
  503.                 time_stamp();
  504.             write_log(t);
  505.                 do_insertion(t, strlen(t));
  506.                 do_blink = TRUE;
  507.                 }
  508.              }
  509.           else {
  510.              if (curr_mode == QUIET_MODE) {
  511.                 time_stamp();
  512.             write_log(t);
  513.             do_insertion(t, strlen(t));
  514.                 }
  515.              if (match_exp(filter[curr_filter].end, filter[curr_filter].ecircf, t)) {
  516.                 curr_mode = NORMAL_MODE;
  517.                 curr_filter = -1;
  518.                 }
  519.              }
  520.           }
  521.        }
  522.     window_set(text, TEXTSW_UPDATE_SCROLLBAR, 0);
  523.     if (do_blink) {
  524.        if (pop_open)
  525.           window_set(bf, FRAME_CLOSED, FALSE, 0);
  526.        if (window_get(bf, FRAME_CLOSED) && !blinking) {
  527.           window_set(bf, FRAME_ICON, bad, 0);
  528.           blinking = TRUE;
  529.           bad_is_up = TRUE;
  530.           menu_set(stop_blink, MENU_INACTIVE, FALSE, 0);
  531.           }
  532.        beep_count = beep_amount;
  533.        notify_set_itimer_func(bf, blink_proc, ITIMER_REAL, &timer, NULL);
  534.        }
  535.     return(NOTIFY_DONE);
  536. }
  537.  
  538. /************************************************************************/
  539. /*    Routines which parse options, create windows, and main()    */
  540. /************************************************************************/
  541.  
  542. /************************************************************************/
  543. static    parse_options(argc, argv)
  544.  
  545. int    *argc;
  546. char    **argv;
  547.  
  548. {    char    *s, c;
  549.  
  550.     strcpy(good_icon, ICON_DIRECTORY);
  551.     strcat(good_icon, GOOD_ICON);
  552.     strcpy(bad_icon, ICON_DIRECTORY);
  553.     strcat(bad_icon, BAD_ICON);
  554.     strcpy(inv_icon, ICON_DIRECTORY);
  555.     strcat(inv_icon, INVERSE_ICON);
  556.  
  557.     strcpy(filter_path, getenv("HOME"));
  558.     strcat(filter_path, "/.contool");
  559.  
  560.     while ((c = getopt(argc, argv, "b:c:d:f:g:l:o:pr:s:?", &s)) != EOF)
  561.        switch (c) {
  562.           case 'b' : strcpy(bad_icon, s);
  563.                    break;
  564.           case 'c' : strcpy(filter_path, s);
  565.                    explicit_filters = TRUE;
  566.                    break;
  567.           case 'd' : if (verify(s, "0123456789"))
  568.                       delete_amt = atoi(s);
  569.                    else {
  570.                       fprintf(stderr, "%s: invalid delete amount: %s\n", program, s);
  571.                       exit(1);
  572.                       }
  573.                    break;
  574.           case 'f' : strcpy(inv_icon, s);
  575.                    break;
  576.           case 'g' : strcpy(good_icon, s);
  577.                    break;
  578.           case 'l' : if (verify(s, "0123456789"))
  579.                       window_set(text, TEXTSW_MEMORY_MAXIMUM, (size_limit = atoi(s)) + TEXT_SIZE_FUZZ, 0);
  580.                    else {
  581.                       fprintf(stderr, "%s: invalid message limit: %s\n", program, s);
  582.                       exit(1);
  583.                       }
  584.                    break;
  585.           case 'o':  if ((logfile = fopen(s, "a")) == NULL) {
  586.                    fprintf(stderr, "%s : can't open logfile: %s\n", program, s);
  587.                 exit(1);
  588.                  }
  589.                  break;
  590.           case 'p' : pop_open = TRUE;
  591.                    break;
  592.           case 'r' : if (verify(s, "0123456789"))
  593.                       resolution = atoi(s);
  594.                    else {
  595.                       fprintf(stderr, "%s: invalid timestamp resolution: %s\n", program, s);
  596.                       exit(1);
  597.                       }
  598.                    break;
  599.           case 's' : if (verify(s, "0123456789"))
  600.                       beep_amount = atoi(s);
  601.                    else {
  602.                       fprintf(stderr, "%s: invalid beep count: %s\n", program, s);
  603.                       exit(1);
  604.                       }
  605.                    break;
  606.           case '?' : fprintf(stderr, ct_usage);
  607.                    exit(0);
  608.                    break;
  609.           default  : fprintf(stderr, ct_usage);
  610.                      exit(1);
  611.           }
  612. }
  613.  
  614. /************************************************************************/
  615. static    load_icons()
  616.  
  617. {    char    msg[IL_ERRORMSG_SIZE];
  618.  
  619.     if ((good_pr = icon_load_mpr(good_icon, msg)) == NULL) {
  620.        fprintf(stderr, "%s: %s\n", program, msg);
  621.        exit(1);
  622.        }
  623.     good = icon_create(ICON_IMAGE, good_pr,
  624.                ICON_LABEL, "",
  625.                ICON_WIDTH, good_pr->pr_size.x,
  626.                ICON_HEIGHT, good_pr->pr_size.y,
  627.                0);
  628.     icon_width = good_pr->pr_size.x;
  629.     icon_height = good_pr->pr_size.y;
  630.     if ((bad_pr = icon_load_mpr(bad_icon, msg)) == NULL) {
  631.        fprintf(stderr, "%s: %s\n", program, msg);
  632.        exit(1);
  633.        }
  634.     bad = icon_create(ICON_IMAGE, bad_pr,
  635.               ICON_LABEL, "",
  636.               ICON_WIDTH, bad_pr->pr_size.x,
  637.               ICON_HEIGHT, bad_pr->pr_size.y,
  638.               0);
  639.     if (bad_pr->pr_size.x > icon_width)
  640.        icon_width = bad_pr->pr_size.x;
  641.     if (bad_pr->pr_size.y > icon_height)
  642.        icon_height = bad_pr->pr_size.y;
  643.     if (*inv_icon == '\0')
  644.        strcpy(inv_icon, bad_icon);
  645.     if ((inv_pr = icon_load_mpr(inv_icon, msg)) == NULL) {
  646.        fprintf(stderr, "%s: %s\n", program, msg);
  647.        exit(1);
  648.        }
  649.     inverse = icon_create(ICON_IMAGE, inv_pr,
  650.                   ICON_LABEL, "",
  651.                   ICON_WIDTH, inv_pr->pr_size.x,
  652.                   ICON_HEIGHT, inv_pr->pr_size.y,
  653.                   0);
  654.     if (inv_pr->pr_size.x > icon_width)
  655.        icon_width = inv_pr->pr_size.x;
  656.     if (inv_pr->pr_size.y > icon_height)
  657.        icon_height = inv_pr->pr_size.y;
  658.     window_set(bf, FRAME_ICON, good, 0);
  659. }
  660.  
  661. /************************************************************************/
  662. main(argc, argv)
  663.  
  664. int    argc;
  665. char    **argv;
  666.  
  667. {    char    *path, *open_psuedo_tty(), **saveargs();
  668.     int    i;
  669.     Menu    menu;
  670.  
  671.     program = strsave(argv[0]);
  672.  
  673.     bf = window_create(NULL, FRAME, 
  674.                   FRAME_ARGC_PTR_ARGV, &argc, argv,
  675.                   FRAME_LABEL, TOOL_LABEL,
  676.                0);
  677.     text = window_create(bf, TEXTSW, 
  678.                     TEXTSW_DISABLE_CD, TRUE,
  679.                     TEXTSW_DISABLE_LOAD, TRUE, 
  680.                     TEXTSW_AGAIN_RECORDING, FALSE,
  681.                     TEXTSW_IGNORE_LIMIT, TEXTSW_INFINITY,
  682.                     TEXTSW_MEMORY_MAXIMUM, size_limit + TEXT_SIZE_FUZZ,
  683.                  0);
  684.     open_rect = *((Rect *) window_get(bf, FRAME_OPEN_RECT));
  685.  
  686.     argv = saveargs(argc, argv);
  687.     parse_options(&argc, argv);
  688.     if (argc != 1) {
  689.        fprintf(stderr, ct_usage);
  690.        exit(1);
  691.        }
  692.  
  693.     load_icons();
  694.  
  695.     path = open_psuedo_tty(&master, "r", &slave, "w");
  696.     if (master == NULL) {
  697.        fprintf(stderr, "%s: couldn't open any psuedo-tty\n");
  698.        exit(1);
  699.        }
  700.     if (slave == NULL) {
  701.        fprintf(stderr, "%s: couldn't open slave side of %s\n", program, path);
  702.        exit(1);
  703.        }
  704.  
  705.     i = fcntl(fileno(master), F_GETFL, 0);
  706.     i |= FNDELAY;
  707.     if (fcntl(fileno(master), F_SETFL, i) == -1) {
  708.        fprintf(stderr, "%s: could not force %s to non-blocking i/o\n", program, path);
  709.        exit(1);
  710.        }
  711.  
  712.     acquire_console(path);
  713.  
  714.     stop_blink = menu_create_item(MENU_STRING, "Stop Blinking",
  715.                       MENU_INACTIVE, TRUE,
  716.                       MENU_ACTION_PROC, stop_blinking,
  717.                       0);
  718.     menu = menu_create(MENU_APPEND_ITEM, stop_blink,
  719.                MENU_ACTION_ITEM, "Become Console", acquire_console,
  720.                MENU_ACTION_ITEM, "Clear Messages", clear_messages,
  721.                MENU_PULLRIGHT_ITEM, "Frame", window_get(bf, WIN_MENU),
  722.                0);
  723.     window_set(bf, WIN_MENU, menu, 0);
  724.  
  725.     notify_set_input_func(bf, input_func, fileno(master));
  726.     notify_interpose_destroy_func(bf, destroy_proc);
  727.     notify_interpose_event_func(bf, close_proc, NOTIFY_SAFE);
  728.  
  729.     load_filters();
  730.  
  731.     window_main_loop(bf);
  732. }
  733.