home *** CD-ROM | disk | FTP | other *** search
/ vim.ftp.fu-berlin.de / 2015-02-03.vim.ftp.fu-berlin.de.tar / vim.ftp.fu-berlin.de / unix / vim-6.2.tar.bz2 / vim-6.2.tar / vim62 / src / netbeans.c < prev    next >
Encoding:
C/C++ Source or Header  |  2003-06-01  |  68.2 KB  |  2,983 lines

  1. /* vi:set ts=8 sts=4 sw=4:
  2.  *
  3.  * VIM - Vi IMproved    by Bram Moolenaar
  4.  *            Netbeans integration by David Weatherford
  5.  *
  6.  * Do ":help uganda"  in Vim to read copying and usage conditions.
  7.  * Do ":help credits" in Vim to see a list of people who contributed.
  8.  */
  9.  
  10. /*
  11.  * Implements client side of org.netbeans.modules.emacs editor
  12.  * integration protocol.  Be careful!  The protocol uses offsets
  13.  * which are *between* characters, whereas vim uses line number
  14.  * and column number which are *on* characters.
  15.  * See ":help netbeans-protocol" for explanation.
  16.  */
  17.  
  18. #include "vim.h"
  19.  
  20. #if defined(FEAT_NETBEANS_INTG) || defined(PROTO)
  21.  
  22. /* Note: when making changes here also adjust configure.in. */
  23. #include <stdarg.h>
  24. #include <fcntl.h>
  25. #include <netdb.h>
  26. #include <netinet/in.h>
  27. #include <sys/socket.h>
  28. #ifdef HAVE_LIBGEN_H
  29. # include <libgen.h>
  30. #endif
  31.  
  32. #include "version.h"
  33.  
  34. #define INET_SOCKETS
  35.  
  36. #define GUARDED        10000 /* typenr for "guarded" annotation */
  37. #define GUARDEDOFFSET 1000000 /* base for "guarded" sign id's */
  38.  
  39. /* The first implementation (working only with Netbeans) returned "1.1".  The
  40.  * protocol implemented here also supports A-A-P. */
  41. static char *ExtEdProtocolVersion = "2.1";
  42.  
  43. static long pos2off __ARGS((buf_T *, pos_T *));
  44. static pos_T *off2pos __ARGS((buf_T *, long));
  45. static pos_T *get_off_or_lnum __ARGS((buf_T *buf, char_u **argp));
  46. static long get_buf_size __ARGS((buf_T *));
  47.  
  48. static void netbeans_connect __ARGS((void));
  49.  
  50. static void nb_init_graphics __ARGS((void));
  51. static void coloncmd __ARGS((char *cmd, ...));
  52. #ifdef FEAT_GUI_MOTIF
  53. static void messageFromNetbeans __ARGS((XtPointer, int *, XtInputId *));
  54. #endif
  55. #ifdef FEAT_GUI_GTK
  56. static void messageFromNetbeans __ARGS((gpointer, gint, GdkInputCondition));
  57. #endif
  58. static void nb_parse_cmd __ARGS((char_u *));
  59. static int  nb_do_cmd __ARGS((int, char_u *, int, int, char_u *));
  60. static void nb_send __ARGS((char *buf, char *fun));
  61. #ifdef FEAT_BEVAL
  62. static void netbeans_beval_cb __ARGS((BalloonEval *beval, int state));
  63. #endif
  64.  
  65. static int sd = -1;            /* socket fd for Netbeans connection */
  66. #ifdef FEAT_GUI_MOTIF
  67. static XtInputId inputHandler;        /* Cookie for input */
  68. #endif
  69. #ifdef FEAT_GUI_GTK
  70. static gint inputHandler;        /* Cookie for input */
  71. #endif
  72. static int cmdno;            /* current command number for reply */
  73. static int haveConnection = FALSE;    /* socket is connected and
  74.                        initialization is done */
  75. static int oldFire = 1;
  76. static int exit_delay = 2;        /* exit delay in seconds */
  77.  
  78. #ifdef FEAT_BEVAL
  79. # if defined(FEAT_GUI_MOTIF) || defined(FEAT_GUI_ATHENA)
  80. extern Widget    textArea;
  81. # endif
  82. BalloonEval    *balloonEval = NULL;
  83. #endif
  84.  
  85. /*
  86.  * Include the debugging code if wanted.
  87.  */
  88. #ifdef NBDEBUG
  89. # include "nbdebug.c"
  90. #endif
  91.  
  92. /* Connect back to Netbeans process */
  93. #if defined(FEAT_GUI_MOTIF) || defined(PROTO)
  94.     void
  95. netbeans_Xt_connect(void *context)
  96. {
  97.     netbeans_connect();
  98.     if (sd > 0)
  99.     {
  100.     /* tell notifier we are interested in being called
  101.      * when there is input on the editor connection socket
  102.      */
  103.     inputHandler = XtAppAddInput((XtAppContext)context, sd,
  104.                  (XtPointer)(XtInputReadMask + XtInputExceptMask),
  105.                            messageFromNetbeans, NULL);
  106.     }
  107. }
  108.  
  109.     static void
  110. netbeans_disconnect(void)
  111. {
  112.     if (inputHandler != (XtInputId)NULL)
  113.     {
  114.     XtRemoveInput(inputHandler);
  115.     inputHandler = (XtInputId)NULL;
  116.     }
  117.     sd = -1;
  118.     haveConnection = FALSE;
  119. }
  120. #endif /* FEAT_MOTIF_GUI */
  121.  
  122. #if defined(FEAT_GUI_GTK) || defined(PROTO)
  123.     void
  124. netbeans_gtk_connect(void)
  125. {
  126. # ifdef FEAT_BEVAL
  127.     /*
  128.      * Set up the Balloon Expression Evaluation area.
  129.      * Always create it but disable it when 'ballooneval' isn't set.
  130.      */
  131.     balloonEval = gui_mch_create_beval_area(gui.drawarea, NULL,
  132.                         &netbeans_beval_cb, NULL);
  133.     if (!p_beval)
  134.     gui_mch_disable_beval_area(balloonEval);
  135. # endif
  136.  
  137.     netbeans_connect();
  138.     if (sd > 0)
  139.     {
  140.     /*
  141.      * Tell gdk we are interested in being called when there
  142.      * is input on the editor connection socket
  143.      */
  144.     inputHandler = gdk_input_add(sd, (GdkInputCondition)
  145.         ((int)GDK_INPUT_READ + (int)GDK_INPUT_EXCEPTION),
  146.                            messageFromNetbeans, NULL);
  147.     }
  148. }
  149.  
  150.     static void
  151. netbeans_disconnect(void)
  152. {
  153.     if (inputHandler != 0)
  154.     {
  155.     gdk_input_remove(inputHandler);
  156.     inputHandler = 0;
  157.     }
  158.     sd = -1;
  159.     haveConnection = FALSE;
  160. }
  161. #endif /* FEAT_GUI_GTK */
  162.  
  163.     static void
  164. netbeans_connect(void)
  165. {
  166. #ifdef INET_SOCKETS
  167.     struct sockaddr_in    server;
  168.     struct hostent *    host;
  169.     int            port;
  170. #else
  171.     struct sockaddr_un    server;
  172. #endif
  173.     char    buf[32];
  174.     char *    hostname;
  175.     char *    address;
  176.     char *    password;
  177.  
  178.     /* netbeansArg is -nb or -nb:<host>:<addr>:<password> */
  179.     if (netbeansArg[3] == ':')
  180.     netbeansArg += 4;
  181.     else
  182.     netbeansArg = NULL;
  183.  
  184.     hostname = netbeansArg;
  185.     if (hostname == NULL || *hostname == '\0')
  186.     hostname = getenv("__NETBEANS_HOST");
  187.     if (hostname == NULL || *hostname == '\0')
  188.     hostname = "localhost"; /* default */
  189.  
  190.     address = strchr(hostname, ':');
  191.     if (address != NULL)
  192.     *address++ = '\0';
  193.     else
  194.     address = getenv("__NETBEANS_SOCKET");
  195.     if (address == NULL || *address == '\0')
  196.     address = "3219";  /* default */
  197.  
  198.     password = strchr(address, ':');
  199.     if (password != NULL)
  200.     *password++ = '\0';
  201.     else
  202.     password = getenv("__NETBEANS_VIM_PASSWORD");
  203.     if (password == NULL || *password == '\0')
  204.     password = "changeme"; /* default */
  205.  
  206. #ifdef INET_SOCKETS
  207.     port = atoi(address);
  208.  
  209.     if ((sd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
  210.     {
  211.     perror("socket() in netbeans_connect()");
  212.     return;
  213.     }
  214.  
  215.     /* Get the server internet address and put into addr structure */
  216.     /* fill in the socket address structure and connect to server */
  217.     memset((char *)&server, '\0', sizeof(server));
  218.     server.sin_family = AF_INET;
  219.     server.sin_port = htons(port);
  220.     if ((host = gethostbyname(hostname)) == NULL)
  221.     {
  222.     if (access(hostname, R_OK) >= 0)
  223.     {
  224.         /* DEBUG: input file */
  225.         sd = open(hostname, O_RDONLY);
  226.         return;
  227.     }
  228.     perror("gethostbyname() in netbeans_connect()");
  229.     sd = -1;
  230.     return;
  231.     }
  232.     memcpy((char *)&server.sin_addr, host->h_addr, host->h_length);
  233. #else
  234.     if ((sd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
  235.     {
  236.     perror("socket()");
  237.     return;
  238.     }
  239.  
  240.     server.sun_family = AF_UNIX;
  241.     strcpy(server.sun_path, address);
  242. #endif
  243.     /* Connect to server */
  244.     if (connect(sd, (struct sockaddr *)&server, sizeof(server)))
  245.     {
  246.     nbdebug(("netbeans_connect: Connect failed with errno %d\n", errno));
  247.     if (errno == ECONNREFUSED)
  248.     {
  249.         close(sd);
  250. #ifdef INET_SOCKETS
  251.         if ((sd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
  252.         {
  253.         perror("socket()#2 in netbeans_connect()");
  254.         return;
  255.         }
  256. #else
  257.         if ((sd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
  258.         {
  259.         perror("socket()#2 in netbeans_connect()");
  260.         return;
  261.         }
  262. #endif
  263.         if (connect(sd, (struct sockaddr *)&server, sizeof(server)))
  264.         {
  265.         int retries = 36;
  266.         int success = FALSE;
  267.         while (retries--
  268.                  && ((errno == ECONNREFUSED) || (errno == EINTR)))
  269.         {
  270.             nbdebug(("retrying...\n"));
  271.             sleep(5);
  272.             if (connect(sd, (struct sockaddr *)&server,
  273.                 sizeof(server)) == 0)
  274.             {
  275.             success = TRUE;
  276.             break;
  277.             }
  278.         }
  279.         if (!success)
  280.         {
  281.             /* Get here when the server can't be found. */
  282.             perror(_("Cannot connect to Netbeans #2"));
  283.             getout(1);
  284.         }
  285.         }
  286.  
  287.     }
  288.     else
  289.     {
  290.         perror(_("Cannot connect to Netbeans"));
  291.         getout(1);
  292.     }
  293.     }
  294.  
  295.     sprintf(buf, "AUTH %s\n", password);
  296.     nb_send(buf, "netbeans_connect");
  297.  
  298.     sprintf(buf, "0:version=0 \"%s\"\n", ExtEdProtocolVersion);
  299.     nb_send(buf, "externaleditor_version");
  300.  
  301.     nbdebug(("netbeans_connect: Connection succeeded\n"));
  302.  
  303. /*    nb_init_graphics();  delay until needed */
  304.  
  305.     haveConnection = TRUE;
  306.  
  307.     return;
  308. }
  309.  
  310.  
  311. struct keyqueue
  312. {
  313.     int             key;
  314.     struct keyqueue *next;
  315.     struct keyqueue *prev;
  316. };
  317.  
  318. typedef struct keyqueue keyQ_T;
  319.  
  320. static keyQ_T keyHead; /* dummy node, header for circular queue */
  321.  
  322.  
  323. /*
  324.  * Queue up key commands sent from netbeans.
  325.  */
  326.     static void
  327. postpone_keycommand(int key)
  328. {
  329.     keyQ_T *node;
  330.  
  331.     node = (keyQ_T *)alloc(sizeof(keyQ_T));
  332.  
  333.     if (keyHead.next == NULL) /* initialize circular queue */
  334.     {
  335.     keyHead.next = &keyHead;
  336.     keyHead.prev = &keyHead;
  337.     }
  338.  
  339.     /* insert node at tail of queue */
  340.     node->next = &keyHead;
  341.     node->prev = keyHead.prev;
  342.     keyHead.prev->next = node;
  343.     keyHead.prev = node;
  344.  
  345.     node->key = key;
  346. }
  347.  
  348. /*
  349.  * Handle any queued-up NetBeans keycommands to be send.
  350.  */
  351.     static void
  352. handle_key_queue(void)
  353. {
  354.     while (keyHead.next && keyHead.next != &keyHead)
  355.     {
  356.     /* first, unlink the node */
  357.     keyQ_T *node = keyHead.next;
  358.     keyHead.next = node->next;
  359.     node->next->prev = node->prev;
  360.  
  361.     /* now, send the keycommand */
  362.     netbeans_keycommand(node->key);
  363.  
  364.     /* Finally, dispose of the node */
  365.     vim_free(node);
  366.     }
  367. }
  368.  
  369.  
  370. struct cmdqueue
  371. {
  372.     char_u        *buffer;
  373.     struct cmdqueue *next;
  374.     struct cmdqueue *prev;
  375. };
  376.  
  377. typedef struct cmdqueue queue_T;
  378.  
  379. static queue_T head;  /* dummy node, header for circular queue */
  380.  
  381.  
  382. /*
  383.  * Put the buffer on the work queue; possibly save it to a file as well.
  384.  */
  385.     static void
  386. save(char_u *buf, int len)
  387. {
  388.     queue_T *node;
  389.  
  390.     node = (queue_T *)alloc(sizeof(queue_T));
  391.     if (node == NULL)
  392.     return;        /* out of memory */
  393.     node->buffer = alloc(len + 1);
  394.     if (node->buffer == NULL)
  395.     {
  396.     vim_free(node);
  397.     return;        /* out of memory */
  398.     }
  399.     mch_memmove(node->buffer, buf, (size_t)len);
  400.     node->buffer[len] = NUL;
  401.  
  402.     if (head.next == NULL)   /* initialize circular queue */
  403.     {
  404.     head.next = &head;
  405.     head.prev = &head;
  406.     }
  407.  
  408.     /* insert node at tail of queue */
  409.     node->next = &head;
  410.     node->prev = head.prev;
  411.     head.prev->next = node;
  412.     head.prev = node;
  413.  
  414. #ifdef NBDEBUG
  415.     {
  416.     static int outfd = -2;
  417.  
  418.     /* possibly write buffer out to a file */
  419.     if (outfd == -3)
  420.         return;
  421.  
  422.     if (outfd == -2)
  423.     {
  424.         char *file = getenv("__NETBEANS_SAVE");
  425.         if (file == NULL)
  426.         outfd = -3;
  427.         else
  428.         outfd = open(file, O_WRONLY|O_CREAT|O_TRUNC, 0666);
  429.     }
  430.  
  431.     if (outfd >= 0)
  432.         write(outfd, buf, len);
  433.     }
  434. #endif
  435. }
  436.  
  437.  
  438. /*
  439.  * While there's still a command in the work queue, parse and execute it.
  440.  */
  441.     static void
  442. nb_parse_messages(void)
  443. {
  444.     char_u    *p;
  445.     queue_T    *node;
  446.  
  447.     while (head.next != &head)
  448.     {
  449.     node = head.next;
  450.  
  451.     /* Locate the first line in the first buffer. */
  452.     p = vim_strchr(node->buffer, '\n');
  453.     if (p == NULL)
  454.     {
  455.         /* Command isn't complete.  If there is no following buffer,
  456.          * return (wait for more). If there is another buffer following,
  457.          * prepend the text to that buffer and delete this one.  */
  458.         if (node->next == &head)
  459.         return;
  460.         p = alloc(STRLEN(node->buffer) + STRLEN(node->next->buffer) + 1);
  461.         if (p == NULL)
  462.         return;        /* out of memory */
  463.         STRCPY(p, node->buffer);
  464.         STRCAT(p, node->next->buffer);
  465.         vim_free(node->next->buffer);
  466.         node->next->buffer = p;
  467.  
  468.         /* dispose of the node and buffer */
  469.         head.next = node->next;
  470.         node->next->prev = node->prev;
  471.         vim_free(node->buffer);
  472.         vim_free(node);
  473.     }
  474.     else
  475.     {
  476.         /* There is a complete command at the start of the buffer.
  477.          * Terminate it with a NUL.  When no more text is following unlink
  478.          * the buffer.  Do this before executing, because new buffers can
  479.          * be added while busy handling the command. */
  480.         *p++ = NUL;
  481.         if (*p == NUL)
  482.         {
  483.         head.next = node->next;
  484.         node->next->prev = node->prev;
  485.         }
  486.  
  487.         /* now, parse and execute the commands */
  488.         nb_parse_cmd(node->buffer);
  489.  
  490.         if (*p == NUL)
  491.         {
  492.         /* buffer finished, dispose of the node and buffer */
  493.         vim_free(node->buffer);
  494.         vim_free(node);
  495.         }
  496.         else
  497.         {
  498.         /* more follows, move to the start */
  499.         mch_memmove(node->buffer, p, STRLEN(p) + 1);
  500.         }
  501.     }
  502.     }
  503. }
  504.  
  505. /* Buffer size for reading incoming messages. */
  506. #define MAXMSGSIZE 4096
  507.  
  508. /*
  509.  * Read and process a command from netbeans.
  510.  */
  511. /*ARGSUSED*/
  512. #ifdef FEAT_GUI_MOTIF
  513.     static void
  514. messageFromNetbeans(XtPointer clientData, int *unused1, XtInputId *unused2)
  515. #endif
  516. #ifdef FEAT_GUI_GTK
  517.     static void
  518. messageFromNetbeans(gpointer clientData, gint unused1,
  519.                             GdkInputCondition unused2)
  520. #endif
  521. {
  522.     static char_u    *buf = NULL;
  523.     int            len;
  524.     int            readlen = 0;
  525.     static int        level = 0;
  526.  
  527.     if (sd < 0)
  528.     {
  529.     nbdebug(("messageFromNetbeans() called without a socket\n"));
  530.     return;
  531.     }
  532.  
  533.     ++level;  /* recursion guard; this will be called from the X event loop */
  534.  
  535.     /* Allocate a buffer to read into. */
  536.     if (buf == NULL)
  537.     {
  538.     buf = alloc(MAXMSGSIZE);
  539.     if (buf == NULL)
  540.         return;    /* out of memory! */
  541.     }
  542.  
  543.     /* Keep on reading for as long as there is something to read. */
  544.     for (;;)
  545.     {
  546.     len = read(sd, buf, MAXMSGSIZE);
  547.     if (len <= 0)
  548.         break;    /* error or nothing more to read */
  549.  
  550.     /* Store the read message in the queue. */
  551.     save(buf, len);
  552.     readlen += len;
  553.  
  554.     if (len < MAXMSGSIZE)
  555.         break;    /* did read everything that's available */
  556.     }
  557.  
  558.     if (readlen <= 0)
  559.     {
  560.     /* read error or didn't read anything */
  561.     netbeans_disconnect();
  562.     nbdebug(("messageFromNetbeans: Error in read() from socket\n"));
  563.     if (len < 0)
  564.         perror(_("read from Netbeans socket"));
  565.     return; /* don't try to parse it */;
  566.     }
  567.  
  568.     /* Parse the messages, but avoid recursion. */
  569.     if (level == 1)
  570.     nb_parse_messages();
  571.  
  572.     --level;
  573. }
  574.  
  575. /*
  576.  * Handle one NUL terminated command.
  577.  *
  578.  * format of a command from netbeans:
  579.  *
  580.  *    6:setTitle!84 "a.c"
  581.  *
  582.  *    bufno
  583.  *     colon
  584.  *      cmd
  585.  *        !
  586.  *         cmdno
  587.  *            args
  588.  *
  589.  * for function calls, the ! is replaced by a /
  590.  */
  591.     static void
  592. nb_parse_cmd(char_u *cmd)
  593. {
  594.     char_u    *verb;
  595.     char_u    *q;
  596.     int        bufno;
  597.     int        isfunc = -1;
  598.  
  599.     if (STRCMP(cmd, "DISCONNECT") == 0)
  600.     {
  601.     /* We assume the server knows that we can safely exit! */
  602.     if (sd >= 0)
  603.         close(sd);
  604.     /* Disconnect before exiting, Motif hangs in a Select error
  605.      * message otherwise. */
  606.     netbeans_disconnect();
  607.     getout(0);
  608.     /* NOTREACHED */
  609.     }
  610.  
  611.     if (STRCMP(cmd, "DETACH") == 0)
  612.     {
  613.     /* The IDE is breaking the connection. */
  614.     if (sd >= 0)
  615.         close(sd);
  616.     netbeans_disconnect();
  617.     return;
  618.     }
  619.  
  620.     bufno = strtol((char *)cmd, (char **)&verb, 10);
  621.  
  622.     if (*verb != ':')
  623.     {
  624.     EMSG2("E627: missing colon: %s", cmd);
  625.     return;
  626.     }
  627.     ++verb; /* skip colon */
  628.  
  629.     for (q = verb; *q; q++)
  630.     {
  631.     if (*q == '!')
  632.     {
  633.         *q++ = NUL;
  634.         isfunc = 0;
  635.         break;
  636.     }
  637.     else if (*q == '/')
  638.     {
  639.         *q++ = NUL;
  640.         isfunc = 1;
  641.         break;
  642.     }
  643.     }
  644.  
  645.     if (isfunc < 0)
  646.     {
  647.     EMSG2("E628: missing ! or / in: %s", cmd);
  648.     return;
  649.     }
  650.  
  651.     cmdno = strtol((char *)q, (char **)&q, 10);
  652.  
  653.     if (nb_do_cmd(bufno, verb, isfunc, cmdno, q) == FAIL)
  654.     {
  655.     nbdebug(("nb_parse_cmd: Command error for \"%s\"\n", cmd));
  656.     EMSG("E629: bad return from nb_do_cmd");
  657.     }
  658. }
  659.  
  660. struct nbbuf_struct
  661. {
  662.     buf_T        *bufp;
  663. #if 0 /* never used */
  664.     unsigned int     netbeansOwns:1;
  665.     unsigned int     fireCaret:1;
  666. #endif
  667.     unsigned int     fireChanges:1;
  668.     unsigned int     initDone:1;
  669.     unsigned int     modified:1;
  670. #if 0  /* never used */
  671.     char        *internalname;
  672. #endif
  673.     char        *displayname;
  674.     char_u        *partial_line;
  675.     int            *signmap;
  676.     ushort         signmaplen;
  677.     ushort         signmapused;
  678. };
  679.  
  680. typedef struct nbbuf_struct nbbuf_T;
  681.  
  682. static nbbuf_T *buf_list = 0;
  683. int buf_list_size = 0;
  684. int buf_list_used = -1; /* last index in use */
  685.  
  686. static char **globalsignmap;
  687. static int globalsignmaplen;
  688. static int globalsignmapused;
  689.  
  690. static int  mapsigntype __ARGS((nbbuf_T *, int localsigntype));
  691. static void addsigntype __ARGS((nbbuf_T *, int localsigntype, char_u *typeName,
  692.             char_u *tooltip, char_u *glyphfile,
  693.             int usefg, int fg, int usebg, int bg));
  694.  
  695. static int curPCtype = -1;
  696.  
  697. /*
  698.  * Get the Netbeans buffer number for the specified buffer.
  699.  */
  700.     static int
  701. nb_getbufno(buf_T *bufp)
  702. {
  703.     int i;
  704.  
  705.     for (i = 0; i <= buf_list_used; i++)
  706.     {
  707.     if (buf_list[i].bufp == bufp)
  708.         return i;
  709.     }
  710.  
  711.     return -1;
  712. }
  713.  
  714. /*
  715.  * Given a Netbeans buffer number, return the netbeans buffer.
  716.  * Returns NULL for 0 or a negative number. A 0 bufno means a
  717.  * non-buffer related command has been sent.
  718.  */
  719.     static nbbuf_T *
  720. nb_get_buf(int bufno)
  721. {
  722.     /* find or create a buffer with the given number */
  723.     int incr;
  724.  
  725.     if (bufno <= 0)
  726.     return NULL;
  727.  
  728.     if (!buf_list)
  729.     {
  730.     /* initialize */
  731.     buf_list = (nbbuf_T *)alloc_clear(100 * sizeof(nbbuf_T));
  732.     buf_list_size = 100;
  733.     }
  734.     if (bufno > buf_list_used) /* new */
  735.     {
  736.     if (bufno >= buf_list_size) /* grow list */
  737.     {
  738.         incr = 100;
  739.         buf_list_size += incr;
  740.         buf_list = (nbbuf_T *)vim_realloc(
  741.                 buf_list, buf_list_size * sizeof(nbbuf_T));
  742.         memset(buf_list + buf_list_size - incr, 0, incr * sizeof(nbbuf_T));
  743.     }
  744.  
  745.     while (buf_list_used < bufno)
  746.     {
  747.         /* Default is to fire text changes. */
  748.         buf_list[buf_list_used].fireChanges = 1;
  749.         ++buf_list_used;
  750.     }
  751.     }
  752.  
  753.     return buf_list + bufno;
  754. }
  755.  
  756. /*
  757.  * Return the number of buffers that are modified.
  758.  */
  759.     static int
  760. count_changed_buffers(void)
  761. {
  762.     buf_T    *bufp;
  763.     int        n;
  764.  
  765.     n = 0;
  766.     for (bufp = firstbuf; bufp != NULL; bufp = bufp->b_next)
  767.     if (bufp->b_changed)
  768.         ++n;
  769.     return n;
  770. }
  771.  
  772. /*
  773.  * End the netbeans session.
  774.  */
  775.     void
  776. netbeans_end(void)
  777. {
  778.     int i;
  779.     static char buf[128];
  780.  
  781.     if (!haveConnection)
  782.     return;
  783.  
  784.     for (i = 0; i <= buf_list_used; i++)
  785.     {
  786.     if (!buf_list[i].bufp)
  787.         continue;
  788.     if (netbeansForcedQuit)
  789.     {
  790.         /* mark as unmodified so NetBeans won't put up dialog on "killed" */
  791.         sprintf(buf, "%d:unmodified=%d\n", i, cmdno);
  792.         nbdebug(("EVT: %s", buf));
  793.         nb_send(buf, "netbeans_end");
  794.     }
  795.     sprintf(buf, "%d:killed=%d\n", i, cmdno);
  796.     nbdebug(("EVT: %s", buf));
  797. /*    nb_send(buf, "netbeans_end");    avoid "write failed" messages */
  798.     if (sd >= 0)
  799.         write(sd, buf, STRLEN(buf));  /* ignore errors */
  800.     }
  801.  
  802.     /* Give NetBeans a chance to write some clean-up cmds to the socket before
  803.      * we close the connection.  Other clients may set the delay to zero. */
  804.     if (exit_delay > 0)
  805.     sleep(exit_delay);
  806. }
  807.  
  808. /*
  809.  * Send a message to netbeans.
  810.  */
  811.     static void
  812. nb_send(char *buf, char *fun)
  813. {
  814.     if (sd < 0)
  815.     EMSG2("E630: %s(): write while not connected", fun);
  816.     else if (write(sd, buf, STRLEN(buf)) != STRLEN(buf))
  817.     EMSG2("E631: %s(): write failed", fun);
  818. }
  819.  
  820. /*
  821.  * Some input received from netbeans requires a response. This function
  822.  * handles a response with no information (except the command number).
  823.  */
  824.     static void
  825. nb_reply_nil(int cmdno)
  826. {
  827.     char reply[32];
  828.  
  829.     if (!haveConnection)
  830.     return;
  831.  
  832.     sprintf(reply, "%d\n", cmdno);
  833.  
  834.     nbdebug(("    REPLY: %s", reply));
  835.  
  836.     nb_send(reply, "nb_reply_nil");
  837. }
  838.  
  839.  
  840. /*
  841.  * Send a response with text.
  842.  */
  843.     static void
  844. nb_reply_text(int cmdno, char_u *result)
  845. {
  846.     char_u *reply;
  847.  
  848.     if (!haveConnection)
  849.     return;
  850.  
  851.     reply = alloc(STRLEN(result) + 32);
  852.     sprintf((char *)reply, "%d %s\n", cmdno, (char *)result);
  853.  
  854.     nbdebug(("    REPLY: %s", reply));
  855.     nb_send((char *)reply, "nb_reply_text");
  856.  
  857.     vim_free(reply);
  858. }
  859.  
  860.  
  861. /*
  862.  * Send a response with a number result code.
  863.  */
  864.     static void
  865. nb_reply_nr(int cmdno, long result)
  866. {
  867.     char reply[32];
  868.  
  869.     if (!haveConnection)
  870.     return;
  871.  
  872.     sprintf(reply, "%d %ld\n", cmdno, result);
  873.  
  874.     nbdebug(("REPLY: %s", reply));
  875.  
  876.     nb_send(reply, "nb_reply_nr");
  877. }
  878.  
  879.  
  880. /*
  881.  * Encode newline, ret, backslash, double quote for transmission to NetBeans.
  882.  */
  883.     static char_u *
  884. nb_quote(char_u *txt)
  885. {
  886.     char_u *buf = alloc(2 * STRLEN(txt) + 1);
  887.     char_u *p = txt;
  888.     char_u *q = buf;
  889.  
  890.     for (; *p; p++)
  891.     {
  892.     switch (*p)
  893.     {
  894.         case '\"':
  895.         case '\\':
  896.         *q++ = '\\'; *q++ = *p; break;
  897.      /* case '\t': */
  898.      /*     *q++ = '\\'; *q++ = 't'; break; */
  899.         case '\n':
  900.         *q++ = '\\'; *q++ = 'n'; break;
  901.         case '\r':
  902.         *q++ = '\\'; *q++ = 'r'; break;
  903.         default:
  904.         *q++ = *p;
  905.         break;
  906.     }
  907.     }
  908.     *q++ = '\0';
  909.  
  910.     return buf;
  911. }
  912.  
  913.  
  914. /*
  915.  * Remove top level double quotes; convert backslashed chars.
  916.  * Returns an allocated string (NULL for failure).
  917.  * If "endp" is not NULL it is set to the character after the terminating
  918.  * quote.
  919.  */
  920.     static char *
  921. nb_unquote(char_u *p, char_u **endp)
  922. {
  923.     char *result = 0;
  924.     char *q;
  925.     int done = 0;
  926.  
  927.     /* result is never longer than input */
  928.     result = (char *)alloc_clear(STRLEN(p) + 1);
  929.     if (result == NULL)
  930.     return NULL;
  931.  
  932.     if (*p++ != '"')
  933.     {
  934.     nbdebug(("nb_unquote called with string that doesn't start with a quote!: %s", p));
  935.     result[0] = NUL;
  936.     return result;
  937.     }
  938.  
  939.     for (q = result; !done && *p != NUL;)
  940.     {
  941.     switch (*p)
  942.     {
  943.         case '"':
  944.         /*
  945.          * Unbackslashed dquote marks the end, if first char was dquote.
  946.          */
  947.         done = 1;
  948.         break;
  949.  
  950.         case '\\':
  951.         ++p;
  952.         switch (*p)
  953.         {
  954.             case '\\':    *q++ = '\\';    break;
  955.             case 'n':    *q++ = '\n';    break;
  956.             case 't':    *q++ = '\t';    break;
  957.             case 'r':    *q++ = '\r';    break;
  958.             case '"':    *q++ = '"';    break;
  959.         }
  960.         ++p;
  961.         break;
  962.  
  963.         default:
  964.         *q++ = *p++;
  965.     }
  966.     }
  967.  
  968.     if (endp != NULL)
  969.     *endp = p;
  970.  
  971.     return result;
  972. }
  973.  
  974. #define SKIP_STOP 2
  975. #define streq(a,b) (strcmp(a,b) == 0)
  976. static int needupdate = 0;
  977. static int inAtomic = 0;
  978.  
  979. /*
  980.  * Do the actual processing of a single netbeans command or function.
  981.  * The differance between a command and function is that a function
  982.  * gets a response (its required) but a command does not.
  983.  * For arguments see comment for nb_parse_cmd().
  984.  */
  985.     static int
  986. nb_do_cmd(
  987.     int        bufno,
  988.     char_u    *cmd,
  989.     int        func,
  990.     int        cmdno,
  991.     char_u    *args)        /* points to space before arguments or NUL */
  992. {
  993.     int        doupdate = 0;
  994.     long    off = 0;
  995.     nbbuf_T    *buf = nb_get_buf(bufno);
  996.     static int    skip = 0;
  997.     int        retval = OK;
  998.  
  999.     nbdebug(("%s %d: (%d) %s %s\n", (func) ? "FUN" : "CMD", cmdno, bufno, cmd,
  1000.     STRCMP(cmd, "insert") == 0 ? "<text>" : (char *)args));
  1001.  
  1002.     if (func)
  1003.     {
  1004. /* =====================================================================*/
  1005.     if (streq((char *)cmd, "getModified"))
  1006.     {
  1007.         if (buf == NULL || buf->bufp == NULL)
  1008.         /* Return the number of buffers that are modified. */
  1009.         nb_reply_nr(cmdno, (long)count_changed_buffers());
  1010.         else
  1011.         /* Return whether the buffer is modified. */
  1012.         nb_reply_nr(cmdno, (long)buf->bufp->b_changed);
  1013. /* =====================================================================*/
  1014.     }
  1015.     else if (streq((char *)cmd, "saveAndExit"))
  1016.     {
  1017.         /* Note: this will exit Vim if successful. */
  1018.         coloncmd(":confirm qall");
  1019.  
  1020.         /* We didn't exit: return the number of changed buffers. */
  1021.         nb_reply_nr(cmdno, (long)count_changed_buffers());
  1022. /* =====================================================================*/
  1023.     }
  1024.     else if (streq((char *)cmd, "getCursor"))
  1025.     {
  1026.         char_u text[200];
  1027.  
  1028.         /* Note: nb_getbufno() may return -1.  This indicates the IDE
  1029.          * didn't assign a number to the current buffer in response to a
  1030.          * fileOpened event. */
  1031.         sprintf((char *)text, "%d %ld %d %ld",
  1032.             nb_getbufno(curbuf),
  1033.             (long)curwin->w_cursor.lnum,
  1034.             (int)curwin->w_cursor.col,
  1035.             pos2off(curbuf, &curwin->w_cursor));
  1036.         nb_reply_text(cmdno, text);
  1037. /* =====================================================================*/
  1038.     }
  1039.     else if (streq((char *)cmd, "getLength"))
  1040.     {
  1041.         long len = 0;
  1042.  
  1043.         if (buf == NULL || buf->bufp == NULL)
  1044.         {
  1045.         nbdebug(("    null bufp in getLength"));
  1046.         EMSG("E632: null bufp in getLength");
  1047.         retval = FAIL;
  1048.         }
  1049.         else
  1050.         {
  1051.         len = get_buf_size(buf->bufp);
  1052.         /* adjust for a partial last line */
  1053.         if (buf->partial_line != NULL)
  1054.         {
  1055.             nbdebug(("    Adjusting buffer len for partial last line: %d\n",
  1056.                 STRLEN(buf->partial_line)));
  1057.             len += STRLEN(buf->partial_line);
  1058.         }
  1059.         }
  1060.         nb_reply_nr(cmdno, len);
  1061. /* =====================================================================*/
  1062.     }
  1063.     else if (streq((char *)cmd, "getText"))
  1064.     {
  1065.         long    len;
  1066.         linenr_T    nlines;
  1067.         char_u    *text = NULL;
  1068.         linenr_T    lno = 1;
  1069.         char_u    *p;
  1070.         char_u    *line;
  1071.  
  1072.         if (buf == NULL || buf->bufp == NULL)
  1073.         {
  1074.         nbdebug(("    null bufp in getText"));
  1075.         EMSG("E633: null bufp in getText");
  1076.         retval = FAIL;
  1077.         }
  1078.         else
  1079.         {
  1080.         len = get_buf_size(buf->bufp);
  1081.         nlines = buf->bufp->b_ml.ml_line_count;
  1082.         text = alloc((unsigned)((len > 0)
  1083.                          ? ((len + nlines) * 2) : 4));
  1084.         if (text == NULL)
  1085.         {
  1086.             nbdebug(("    nb_do_cmd: getText has null text field\n"));
  1087.             retval = FAIL;
  1088.         }
  1089.         else
  1090.         {
  1091.             p = text;
  1092.             *p++ = '\"';
  1093.             for (; lno <= nlines ; lno++)
  1094.             {
  1095.             line = nb_quote(ml_get_buf(buf->bufp, lno, FALSE));
  1096.             if (line != NULL)
  1097.             {
  1098.                 STRCPY(p, line);
  1099.                 p += STRLEN(line);
  1100.                 *p++ = '\\';
  1101.                 *p++ = 'n';
  1102.             }
  1103.             vim_free(line);
  1104.             }
  1105.             *p++ = '\"';
  1106.             *p = '\0';
  1107.         }
  1108.         }
  1109.         if (text == NULL)
  1110.         nb_reply_text(cmdno, (char_u *)"");
  1111.         else
  1112.         {
  1113.         nb_reply_text(cmdno, text);
  1114.         vim_free(text);
  1115.         }
  1116. /* =====================================================================*/
  1117.     }
  1118.     else if (streq((char *)cmd, "remove"))
  1119.     {
  1120.         long count;
  1121.         pos_T first, last;
  1122.         pos_T *pos;
  1123.         int oldFire = netbeansFireChanges;
  1124.         int oldSuppress = netbeansSuppressNoLines;
  1125.         int wasChanged;
  1126.  
  1127.         if (skip >= SKIP_STOP)
  1128.         {
  1129.         nbdebug(("    Skipping %s command\n", (char *) cmd));
  1130.         nb_reply_nil(cmdno);
  1131.         return OK;
  1132.         }
  1133.  
  1134.         if (buf == NULL || buf->bufp == NULL)
  1135.         {
  1136.         nbdebug(("    null bufp in remove"));
  1137.         EMSG("E634: null bufp in remove");
  1138.         retval = FAIL;
  1139.         }
  1140.         else
  1141.         {
  1142.         netbeansFireChanges = FALSE;
  1143.         netbeansSuppressNoLines = TRUE;
  1144.  
  1145.         if (curbuf != buf->bufp)
  1146.             set_curbuf(buf->bufp, DOBUF_GOTO);
  1147.         wasChanged = buf->bufp->b_changed;
  1148.         off = strtol((char *)args, (char **)&args, 10);
  1149.         count = strtol((char *)args, (char **)&args, 10);
  1150.         /* delete "count" chars, starting at "off" */
  1151.         pos = off2pos(buf->bufp, off);
  1152.         if (!pos)
  1153.         {
  1154.             nb_reply_text(cmdno, (char_u *)"!bad position");
  1155.             netbeansFireChanges = oldFire;
  1156.             netbeansSuppressNoLines = oldSuppress;
  1157.             return FAIL;
  1158.         }
  1159.         first = *pos;
  1160.         nbdebug(("    FIRST POS: line %d, col %d\n", first.lnum, first.col));
  1161.         pos = off2pos(buf->bufp, off+count-1);
  1162.         if (!pos)
  1163.         {
  1164.             nb_reply_text(cmdno, (char_u *)"!bad count");
  1165.             netbeansFireChanges = oldFire;
  1166.             netbeansSuppressNoLines = oldSuppress;
  1167.             return FAIL;
  1168.         }
  1169.         last = *pos;
  1170.         nbdebug(("    LAST POS: line %d, col %d\n", last.lnum, last.col));
  1171.         curwin->w_cursor = first;
  1172.         doupdate = 1;
  1173.  
  1174.         /* keep part of first line */
  1175.         if (first.lnum == last.lnum && first.col != last.col)
  1176.         {
  1177.             /* deletion is within one line */
  1178.             char_u *p = ml_get(first.lnum);
  1179.             mch_memmove(p + first.col, p + last.col + 1, STRLEN(p + last.col) + 1);
  1180.             nbdebug(("    NEW LINE %d: %s\n", first.lnum, p));
  1181.             ml_replace(first.lnum, p, TRUE);
  1182.         }
  1183.  
  1184.         if (first.lnum < last.lnum)
  1185.         {
  1186.             int i;
  1187.  
  1188.             /* delete signs from the lines being deleted */
  1189.             for (i = first.lnum; i <= last.lnum; i++)
  1190.             {
  1191.             int id = buf_findsign_id(buf->bufp, (linenr_T)i);
  1192.             if (id > 0)
  1193.             {
  1194.                 nbdebug(("    Deleting sign %d on line %d\n", id, i));
  1195.                 buf_delsign(buf->bufp, id);
  1196.             }
  1197.             else
  1198.                 nbdebug(("    No sign on line %d\n", i));
  1199.             }
  1200.  
  1201.             /* delete whole lines */
  1202.             nbdebug(("    Deleting lines %d through %d\n", first.lnum, last.lnum));
  1203.             del_lines(last.lnum - first.lnum + 1, FALSE);
  1204.         }
  1205.         buf->bufp->b_changed = wasChanged; /* logically unchanged */
  1206.         netbeansFireChanges = oldFire;
  1207.         netbeansSuppressNoLines = oldSuppress;
  1208.  
  1209.         u_blockfree(buf->bufp);
  1210.         u_clearall(buf->bufp);
  1211.         }
  1212.         nb_reply_nil(cmdno);
  1213. /* =====================================================================*/
  1214.     }
  1215.     else if (streq((char *)cmd, "insert"))
  1216.     {
  1217.         pos_T    *pos;
  1218.         char_u    *to_free;
  1219.         char_u    *nl;
  1220.         int        lnum;
  1221.         pos_T    old_w_cursor;
  1222.         int        old_b_changed;
  1223.  
  1224.         if (skip >= SKIP_STOP)
  1225.         {
  1226.         nbdebug(("    Skipping %s command\n", (char *) cmd));
  1227.         nb_reply_nil(cmdno);
  1228.         return OK;
  1229.         }
  1230.  
  1231.         /* get offset */
  1232.         off = strtol((char *)args, (char **)&args, 10);
  1233.  
  1234.         /* get text to be inserted */
  1235.         ++args; /* skip space */
  1236.         args = to_free = (char_u *)nb_unquote(args, NULL);
  1237.  
  1238.         if (buf == NULL || buf->bufp == NULL)
  1239.         {
  1240.         nbdebug(("    null bufp in insert"));
  1241.         EMSG("E635: null bufp in insert");
  1242.         retval = FAIL;
  1243.         }
  1244.         else if (args != NULL)
  1245.         {
  1246.         oldFire = netbeansFireChanges;
  1247.         netbeansFireChanges = 0;
  1248.  
  1249.         if (curbuf != buf->bufp)
  1250.             set_curbuf(buf->bufp, DOBUF_GOTO);
  1251.         old_b_changed = buf->bufp->b_changed;
  1252.  
  1253.         if (buf->partial_line != NULL)
  1254.         {
  1255.             nbdebug(("    Combining with partial line\n"));
  1256.             off -= STRLEN(buf->partial_line);
  1257.             pos = off2pos(buf->bufp, off);
  1258.             if (pos && pos->col != 0)
  1259.             off -= pos->col;  /* want start of line */
  1260.             buf->partial_line = vim_realloc(buf->partial_line,
  1261.                 STRLEN(buf->partial_line) + STRLEN(args) + 1);
  1262.             STRCAT(buf->partial_line, args);
  1263.             vim_free(to_free);
  1264.             args = buf->partial_line;
  1265.             buf->partial_line = NULL;
  1266.             to_free = args;
  1267.         }
  1268.         pos = off2pos(buf->bufp, off);
  1269.         if (pos)
  1270.         {
  1271.             if (pos->lnum == 0)
  1272.             pos->lnum = 1;
  1273.             nbdebug(("    POSITION: line = %d, col = %d\n",
  1274.                             pos->lnum, pos->col));
  1275.         }
  1276.         else
  1277.         {
  1278.             /* if the given position is not found, assume we want
  1279.              * the end of the file.  See setLocAndSize HACK.
  1280.              */
  1281.             pos->lnum = buf->bufp->b_ml.ml_line_count;
  1282.             nbdebug(("    POSITION: line = %d (EOF)\n",pos->lnum));
  1283.         }
  1284.         lnum = pos->lnum;
  1285.         old_w_cursor = curwin->w_cursor;
  1286.         curwin->w_cursor = *pos;
  1287.  
  1288.         doupdate = 1;
  1289.         while (*args)
  1290.         {
  1291.             nl = (char_u *)strchr((char *)args, '\n');
  1292.             if (!nl)
  1293.             {
  1294.             nbdebug(("    PARTIAL[%d]: %s\n", lnum, args));
  1295.             break;
  1296.             }
  1297.             *nl = '\0';
  1298.             nbdebug(("    INSERT[%d]: %s\n", lnum, args));
  1299.             ml_append((linenr_T)(lnum++ - 1), args,
  1300.                              STRLEN(args) + 1, FALSE);
  1301.             args = nl + 1;
  1302.         }
  1303.         appended_lines_mark(pos->lnum - 1, lnum - pos->lnum);
  1304.  
  1305.         if (*args)
  1306.         {
  1307.             /*
  1308.              * Incomplete line, squirrel away and wait for next insert.
  1309.              */
  1310.             nbdebug(("    PARTIAL-SAVED: %s\n", args));
  1311.             buf->partial_line = vim_realloc(buf->partial_line,
  1312.                                 STRLEN(args) + 1);
  1313.             STRCPY(buf->partial_line, args);
  1314.         }
  1315.         curwin->w_cursor = old_w_cursor;
  1316.  
  1317.         /*
  1318.          * XXX - GRP - Is the next line right? If I've inserted
  1319.          * text the buffer has been updated but not written. Will
  1320.          * netbeans guarantee to write it? Even if I do a :q! ?
  1321.          */
  1322.         buf->bufp->b_changed = old_b_changed; /* logically unchanged */
  1323.         netbeansFireChanges = oldFire;
  1324.  
  1325.         u_blockfree(buf->bufp);
  1326.         u_clearall(buf->bufp);
  1327.         }
  1328.         vim_free(to_free);
  1329.         nb_reply_nil(cmdno); /* or !error */
  1330.     }
  1331.     else
  1332.     {
  1333.         nbdebug(("UNIMPLEMENTED FUNCTION: %s\n", cmd));
  1334.         nb_reply_nil(cmdno);
  1335.         retval = FAIL;
  1336.     }
  1337.     }
  1338.     else /* Not a function; no reply required. */
  1339.     {
  1340. /* =====================================================================*/
  1341.     if (streq((char *)cmd, "create"))
  1342.     {
  1343.         /* Create a buffer without a name. */
  1344.         if (buf == NULL)
  1345.         {
  1346.         EMSG("E636: null buf in create");
  1347.         return FAIL;
  1348.         }
  1349.         vim_free(buf->displayname);
  1350.         buf->displayname = NULL;
  1351.         nbdebug(("    CREATE %d\n", bufno));
  1352.  
  1353.         netbeansReadFile = 0; /* don't try to open disk file */
  1354.         do_ecmd(0, NULL, 0, 0, ECMD_ONE, ECMD_HIDE + ECMD_OLDBUF);
  1355.         netbeansReadFile = 1;
  1356.         buf->bufp = curbuf;
  1357.         maketitle();
  1358.         gui_update_menus(0);
  1359. /* =====================================================================*/
  1360.     }
  1361.     else if (streq((char *)cmd, "startDocumentListen"))
  1362.     {
  1363.         if (buf == NULL)
  1364.         {
  1365.         EMSG("E637: null buf in startDocumentListen");
  1366.         return FAIL;
  1367.         }
  1368.         buf->fireChanges = 1;
  1369. /* =====================================================================*/
  1370.     }
  1371.     else if (streq((char *)cmd, "stopDocumentListen"))
  1372.     {
  1373.         if (buf == NULL)
  1374.         {
  1375.         EMSG("E638: null buf in stopDocumentListen");
  1376.         return FAIL;
  1377.         }
  1378.         buf->fireChanges = 0;
  1379. /* =====================================================================*/
  1380.     }
  1381.     else if (streq((char *)cmd, "setTitle"))
  1382.     {
  1383.         if (buf == NULL)
  1384.         {
  1385.         EMSG("E639: null buf in setTitle");
  1386.         return FAIL;
  1387.         }
  1388.         vim_free(buf->displayname);
  1389.         buf->displayname = nb_unquote(++args, NULL);
  1390.         nbdebug(("    SETTITLE %d %s\n", bufno, buf->displayname));
  1391. /* =====================================================================*/
  1392.     }
  1393.     else if (streq((char *)cmd, "initDone"))
  1394.     {
  1395.         if (buf == NULL || buf->bufp == NULL)
  1396.         {
  1397.         EMSG("E640: null buf in initDone");
  1398.         return FAIL;
  1399.         }
  1400.         doupdate = 1;
  1401.         buf->initDone = 1;
  1402.         if (curbuf != buf->bufp)
  1403.         set_curbuf(buf->bufp, DOBUF_GOTO);
  1404. #if defined(FEAT_AUTOCMD)
  1405.         apply_autocmds(EVENT_BUFREADPOST, 0, 0, FALSE, buf->bufp);
  1406. #endif
  1407.  
  1408.         /* handle any postponed key commands */
  1409.         handle_key_queue();
  1410. /* =====================================================================*/
  1411.     }
  1412.     else if (streq((char *)cmd, "setBufferNumber")
  1413.         || streq((char *)cmd, "putBufferNumber"))
  1414.     {
  1415.         char_u    *to_free;
  1416.         buf_T    *bufp;
  1417.  
  1418.         if (buf == NULL)
  1419.         {
  1420.         EMSG("E641: null buf in setBufferNumber");
  1421.         return FAIL;
  1422.         }
  1423.         to_free = (char_u *)nb_unquote(++args, NULL);
  1424.         if (to_free == NULL)
  1425.         return FAIL;
  1426.         bufp = buflist_findname(to_free);
  1427.         vim_free(to_free);
  1428.         if (bufp == NULL)
  1429.         {
  1430.         EMSG2("E642: File %s not found in setBufferNumber", args);
  1431.         return FAIL;
  1432.         }
  1433.         buf->bufp = bufp;
  1434.  
  1435.         /* "setBufferNumber" has the side effect of jumping to the buffer
  1436.          * (don't know why!).  Don't do that for "putBufferNumber". */
  1437.         if (*cmd != 'p')
  1438.         coloncmd(":buffer %d", bufp->b_fnum);
  1439.         else
  1440.         {
  1441.         buf->initDone = 1;
  1442.  
  1443.         /* handle any postponed key commands */
  1444.         handle_key_queue();
  1445.         }
  1446.  
  1447. #if 0  /* never used */
  1448.         buf->internalname = (char *)alloc_clear(8);
  1449.         sprintf(buf->internalname, "<%d>", bufno);
  1450.         buf->netbeansOwns = 0;
  1451. #endif
  1452. /* =====================================================================*/
  1453.     }
  1454.     else if (streq((char *)cmd, "setFullName"))
  1455.     {
  1456.         if (buf == NULL)
  1457.         {
  1458.         EMSG("E643: null buf in setFullName");
  1459.         return FAIL;
  1460.         }
  1461.         vim_free(buf->displayname);
  1462.         buf->displayname = nb_unquote(++args, NULL);
  1463.         nbdebug(("    SETFULLNAME %d %s\n", bufno, buf->displayname));
  1464.  
  1465.         netbeansReadFile = 0; /* don't try to open disk file */
  1466.         do_ecmd(0, (char_u *)buf->displayname, 0, 0, ECMD_ONE,
  1467.                              ECMD_HIDE + ECMD_OLDBUF);
  1468.         netbeansReadFile = 1;
  1469.         buf->bufp = curbuf;
  1470.         maketitle();
  1471.         gui_update_menus(0);
  1472. /* =====================================================================*/
  1473.     }
  1474.     else if (streq((char *)cmd, "editFile"))
  1475.     {
  1476.         if (buf == NULL)
  1477.         {
  1478.         EMSG("E644: null buf in editFile");
  1479.         return FAIL;
  1480.         }
  1481.         /* Edit a file: like create + setFullName + read the file. */
  1482.         vim_free(buf->displayname);
  1483.         buf->displayname = nb_unquote(++args, NULL);
  1484.         nbdebug(("    EDITFILE %d %s\n", bufno, buf->displayname));
  1485.         do_ecmd(0, (char_u *)buf->displayname, NULL, NULL, ECMD_ONE,
  1486.                              ECMD_HIDE + ECMD_OLDBUF);
  1487.         buf->bufp = curbuf;
  1488.         buf->initDone = 1;
  1489.         doupdate = 1;
  1490. #if defined(FEAT_TITLE)
  1491.         maketitle();
  1492. #endif
  1493.         gui_update_menus(0);
  1494. /* =====================================================================*/
  1495.     }
  1496.     else if (streq((char *)cmd, "setVisible"))
  1497.     {
  1498.         ++args;
  1499.         if (buf == NULL || buf->bufp == NULL)
  1500.         {
  1501. /*        EMSG("E645: null bufp in setVisible"); */
  1502.         return FAIL;
  1503.         }
  1504.         if (streq((char *)args, "T"))
  1505.         {
  1506.         exarg_T exarg;
  1507.         exarg.cmd = (char_u *)"goto";
  1508.         exarg.forceit = FALSE;
  1509.         goto_buffer(&exarg, DOBUF_FIRST, FORWARD, buf->bufp->b_fnum);
  1510.         doupdate = 1;
  1511.  
  1512.         /* Side effect!!!. */
  1513.         if (!gui.starting)
  1514.             gui_mch_set_foreground();
  1515.         }
  1516.         else
  1517.         {
  1518.         /* bury the buffer - not yet */
  1519.         }
  1520. /* =====================================================================*/
  1521.     }
  1522.     else if (streq((char *)cmd, "raise"))
  1523.     {
  1524.         /* Bring gvim to the foreground. */
  1525.         if (!gui.starting)
  1526.         gui_mch_set_foreground();
  1527. /* =====================================================================*/
  1528.     }
  1529.     else if (streq((char *)cmd, "setModified"))
  1530.     {
  1531.         ++args;
  1532.         if (buf == NULL || buf->bufp == NULL)
  1533.         {
  1534. /*        EMSG("E646: null bufp in setModified"); */
  1535.         return FAIL;
  1536.         }
  1537.         if (streq((char *)args, "T"))
  1538.         buf->bufp->b_changed = 1;
  1539.         else
  1540.         buf->bufp->b_changed = 0;
  1541.         buf->modified = buf->bufp->b_changed;
  1542. /* =====================================================================*/
  1543.     }
  1544.     else if (streq((char *)cmd, "setMark"))
  1545.     {
  1546.         /* not yet */
  1547. /* =====================================================================*/
  1548.     }
  1549.     else if (streq((char *)cmd, "showBalloon"))
  1550.     {
  1551. #if defined(FEAT_BEVAL)
  1552.         static char    *text = NULL;
  1553.  
  1554.         /*
  1555.          * Set up the Balloon Expression Evaluation area.
  1556.          * Ignore 'ballooneval' here.
  1557.          * The text pointer must remain valid for a while.
  1558.          */
  1559.         if (balloonEval != NULL)
  1560.         {
  1561.         vim_free(text);
  1562.         text = nb_unquote(++args, NULL);
  1563.         if (text != NULL)
  1564.             gui_mch_post_balloon(balloonEval, (char_u *)text);
  1565.         }
  1566. #endif
  1567. /* =====================================================================*/
  1568.     }
  1569.     else if (streq((char *)cmd, "setDot"))
  1570.     {
  1571.         pos_T *pos;
  1572. #ifdef NBDEBUG
  1573.         char_u *s;
  1574. #endif
  1575.  
  1576.         ++args;
  1577.         if (buf == NULL || buf->bufp == NULL)
  1578.         {
  1579.         EMSG("E647: null bufp in setDot");
  1580.         return FAIL;
  1581.         }
  1582.  
  1583.         if (curbuf != buf->bufp)
  1584.         set_curbuf(buf->bufp, DOBUF_GOTO);
  1585. #ifdef FEAT_VISUAL
  1586.         /* Don't want Visual mode now. */
  1587.         if (VIsual_active)
  1588.         end_visual_mode();
  1589. #endif
  1590. #ifdef NBDEBUG
  1591.         s = args;
  1592. #endif
  1593.         pos = get_off_or_lnum(buf->bufp, &args);
  1594.         if (pos)
  1595.         {
  1596.         curwin->w_cursor = *pos;
  1597.         check_cursor();
  1598.         }
  1599.         else
  1600.         nbdebug(("    BAD POSITION in setDot: %s\n", s));
  1601.  
  1602.         /* gui_update_cursor(TRUE, FALSE); */
  1603.         /* update_curbuf(NOT_VALID); */
  1604.         update_topline();        /* scroll to show the line */
  1605.         update_screen(VALID);
  1606.         setcursor();
  1607.         out_flush();
  1608.         gui_update_cursor(TRUE, FALSE);
  1609.         gui_mch_flush();
  1610.         /* Quit a hit-return or more prompt. */
  1611.         if (State == HITRETURN || State == ASKMORE)
  1612.         {
  1613.         add_to_input_buf((char_u *)"\003", 1);
  1614. #ifdef FEAT_GUI_GTK
  1615.         if (gtk_main_level() > 0)
  1616.             gtk_main_quit();
  1617. #endif
  1618.         }
  1619. /* =====================================================================*/
  1620.     }
  1621.     else if (streq((char *)cmd, "close"))
  1622.     {
  1623. #ifdef NBDEBUG
  1624.         char *name = "<NONE>";
  1625. #endif
  1626.  
  1627.         if (buf == NULL)
  1628.         {
  1629.         EMSG("E648: null buf in close");
  1630.         return FAIL;
  1631.         }
  1632.  
  1633. #ifdef NBDEBUG
  1634.         if (buf->displayname != NULL)
  1635.         name = buf->displayname;
  1636. #endif
  1637. /*        if (buf->bufp == NULL) */
  1638. /*        EMSG("E649: null bufp in close"); */
  1639.         nbdebug(("    CLOSE %d: %s\n", bufno, name));
  1640.         need_mouse_correct = TRUE;
  1641.         if (buf->bufp != NULL)
  1642.         close_buffer(NULL, buf->bufp, 0);
  1643.         doupdate = 1;
  1644. /* =====================================================================*/
  1645.     }
  1646.     else if (streq((char *)cmd, "setStyle")) /* obsolete... */
  1647.     {
  1648.         nbdebug(("    setStyle is obsolete!"));
  1649. /* =====================================================================*/
  1650.     }
  1651.     else if (streq((char *)cmd, "setExitDelay"))
  1652.     {
  1653.         /* New in version 2.1. */
  1654.         exit_delay = strtol((char *)args, (char **)&args, 10);
  1655. /* =====================================================================*/
  1656.     }
  1657.     else if (streq((char *)cmd, "defineAnnoType"))
  1658.     {
  1659. #ifdef FEAT_SIGNS
  1660.         int typeNum;
  1661.         char_u *typeName;
  1662.         char_u *tooltip;
  1663.         char_u *glyphFile;
  1664.         int use_fg = 0;
  1665.         int use_bg = 0;
  1666.         int fg = -1;
  1667.         int bg = -1;
  1668.  
  1669.         if (buf == NULL)
  1670.         {
  1671.         EMSG("E650: null buf in defineAnnoType");
  1672.         return FAIL;
  1673.         }
  1674.  
  1675.         typeNum = strtol((char *)args, (char **)&args, 10);
  1676.         args = skipwhite(args);
  1677.         typeName = (char_u *)nb_unquote(args, &args);
  1678.         args = skipwhite(args + 1);
  1679.         tooltip = (char_u *)nb_unquote(args, &args);
  1680.         args = skipwhite(args + 1);
  1681.         glyphFile = (char_u *)nb_unquote(args, &args);
  1682.         args = skipwhite(args + 1);
  1683.         if (STRNCMP(args, "none", 4) == 0)
  1684.         args += 5;
  1685.         else
  1686.         {
  1687.         use_fg = 1;
  1688.         fg = strtol((char *)args, (char **)&args, 10);
  1689.         }
  1690.         if (STRNCMP(args, "none", 4) == 0)
  1691.         args += 5;
  1692.         else
  1693.         {
  1694.         use_bg = 1;
  1695.         bg = strtol((char *)args, (char **)&args, 10);
  1696.         }
  1697.         if (typeName != NULL && tooltip != NULL && glyphFile != NULL)
  1698.         addsigntype(buf, typeNum, typeName, tooltip, glyphFile,
  1699.                               use_fg, fg, use_bg, bg);
  1700.         else
  1701.         vim_free(typeName);
  1702.  
  1703.         /* don't free typeName; it's used directly in addsigntype() */
  1704.         vim_free(tooltip);
  1705.         vim_free(glyphFile);
  1706.  
  1707. #endif
  1708. /* =====================================================================*/
  1709.     }
  1710.     else if (streq((char *)cmd, "addAnno"))
  1711.     {
  1712. #ifdef FEAT_SIGNS
  1713.         int serNum;
  1714.         int localTypeNum;
  1715.         int typeNum;
  1716. # ifdef NBDEBUG
  1717.         int len;
  1718. # endif
  1719.         pos_T *pos;
  1720.  
  1721.         if (buf == NULL || buf->bufp == NULL)
  1722.         {
  1723.         EMSG("E651: null bufp in addAnno");
  1724.         return FAIL;
  1725.         }
  1726.  
  1727.         doupdate = 1;
  1728.  
  1729.         serNum = strtol((char *)args, (char **)&args, 10);
  1730.  
  1731.         /* Get the typenr specific for this buffer and convert it to
  1732.          * the global typenumber, as used for the sign name. */
  1733.         localTypeNum = strtol((char *)args, (char **)&args, 10);
  1734.         typeNum = mapsigntype(buf, localTypeNum);
  1735.  
  1736.         pos = get_off_or_lnum(buf->bufp, &args);
  1737.  
  1738. # ifdef NBDEBUG
  1739.         len =
  1740. # endif
  1741.         strtol((char *)args, (char **)&args, 10);
  1742. # ifdef NBDEBUG
  1743.         if (len != -1)
  1744.         {
  1745.         nbdebug(("    partial line annotation -- Not Yet Implemented!"));
  1746.         }
  1747. # endif
  1748.         if (serNum >= GUARDEDOFFSET)
  1749.         {
  1750.         nbdebug(("    too many annotations! ignoring..."));
  1751.         return FAIL;
  1752.         }
  1753.         if (pos)
  1754.         {
  1755.         coloncmd(":sign place %d line=%d name=%d buffer=%d",
  1756.                serNum, pos->lnum, typeNum, buf->bufp->b_fnum);
  1757.         if (typeNum == curPCtype)
  1758.             coloncmd(":sign jump %d buffer=%d", serNum,
  1759.                                buf->bufp->b_fnum);
  1760.         }
  1761.         /* XXX only redraw what changed. */
  1762.         redraw_later(CLEAR);
  1763. #endif
  1764. /* =====================================================================*/
  1765.     }
  1766.     else if (streq((char *)cmd, "removeAnno"))
  1767.     {
  1768. #ifdef FEAT_SIGNS
  1769.         int serNum;
  1770.  
  1771.         if (buf == NULL || buf->bufp == NULL)
  1772.         {
  1773.         nbdebug(("    null bufp in removeAnno"));
  1774.         return FAIL;
  1775.         }
  1776.         doupdate = 1;
  1777.         serNum = strtol((char *)args, (char **)&args, 10);
  1778.         coloncmd(":sign unplace %d buffer=%d",
  1779.              serNum, buf->bufp->b_fnum);
  1780.         redraw_buf_later(buf->bufp, NOT_VALID);
  1781. #endif
  1782. /* =====================================================================*/
  1783.     }
  1784.     else if (streq((char *)cmd, "moveAnnoToFront"))
  1785.     {
  1786. #ifdef FEAT_SIGNS
  1787.         nbdebug(("    moveAnnoToFront: Not Yet Implemented!"));
  1788. #endif
  1789. /* =====================================================================*/
  1790.     }
  1791.     else if (streq((char *)cmd, "guard") || streq((char *)cmd, "unguard"))
  1792.     {
  1793.         int len;
  1794.         pos_T first;
  1795.         pos_T last;
  1796.         pos_T *pos;
  1797.         int un = (cmd[0] == 'u');
  1798.         static int guardId = GUARDEDOFFSET;
  1799.  
  1800.         if (skip >= SKIP_STOP)
  1801.         {
  1802.         nbdebug(("    Skipping %s command\n", (char *) cmd));
  1803.         return OK;
  1804.         }
  1805.  
  1806.         nb_init_graphics();
  1807.  
  1808.         if (buf == NULL || buf->bufp == NULL)
  1809.         {
  1810.         nbdebug(("    null bufp in %s command", cmd));
  1811.         return FAIL;
  1812.         }
  1813.         if (curbuf != buf->bufp)
  1814.         set_curbuf(buf->bufp, DOBUF_GOTO);
  1815.         off = strtol((char *)args, (char **)&args, 10);
  1816.         len = strtol((char *)args, 0, 10);
  1817.         pos = off2pos(buf->bufp, off);
  1818.         doupdate = 1;
  1819.         if (!pos)
  1820.         nbdebug(("    no such start pos in %s, %ld\n", cmd, off));
  1821.         else
  1822.         {
  1823.         first = *pos;
  1824.         pos = off2pos(buf->bufp, off + len - 1);
  1825.         if (pos != NULL && pos->col == 0) {
  1826.             /*
  1827.              * In Java Swing the offset is a position between 2
  1828.              * characters. If col == 0 then we really want the
  1829.              * previous line as the end.
  1830.              */
  1831.             pos = off2pos(buf->bufp, off + len - 2);
  1832.         }
  1833.         if (!pos)
  1834.             nbdebug(("    no such end pos in %s, %ld\n",
  1835.                 cmd, off + len - 1));
  1836.         else
  1837.         {
  1838.             long lnum;
  1839.             last = *pos;
  1840.             /* set highlight for region */
  1841.             nbdebug(("    %sGUARD %ld,%d to %ld,%d\n", (un) ? "UN" : "",
  1842.                  first.lnum, first.col,
  1843.                  last.lnum, last.col));
  1844. #ifdef FEAT_SIGNS
  1845.             for (lnum = first.lnum; lnum <= last.lnum; lnum++)
  1846.             {
  1847.             if (un)
  1848.             {
  1849.                 /* never used */
  1850.             }
  1851.             else
  1852.             {
  1853.                 if (buf_findsigntype_id(buf->bufp, lnum,
  1854.                 GUARDED) == 0)
  1855.                 {
  1856.                 coloncmd(
  1857.                     ":sign place %d line=%d name=%d buffer=%d",
  1858.                      guardId++, lnum, GUARDED,
  1859.                      buf->bufp->b_fnum);
  1860.                 }
  1861.             }
  1862.             }
  1863. #endif
  1864.             redraw_buf_later(buf->bufp, NOT_VALID);
  1865.         }
  1866.         }
  1867. /* =====================================================================*/
  1868.     }
  1869.     else if (streq((char *)cmd, "startAtomic"))
  1870.     {
  1871.         inAtomic = 1;
  1872. /* =====================================================================*/
  1873.     }
  1874.     else if (streq((char *)cmd, "endAtomic"))
  1875.     {
  1876.         inAtomic = 0;
  1877.         if (needupdate)
  1878.         {
  1879.         doupdate = 1;
  1880.         needupdate = 0;
  1881.         }
  1882. /* =====================================================================*/
  1883.     }
  1884.     else if (streq((char *)cmd, "version"))
  1885.     {
  1886.         nbdebug(("    Version = %s\n", (char *) args));
  1887.     }
  1888.     /*
  1889.      * Unrecognized command is ignored.
  1890.      */
  1891.     }
  1892.     if (inAtomic && doupdate)
  1893.     {
  1894.     needupdate = 1;
  1895.     doupdate = 0;
  1896.     }
  1897.  
  1898.     if (buf != NULL && buf->initDone && doupdate)
  1899.     {
  1900.     update_screen(NOT_VALID);
  1901.     setcursor();
  1902.     out_flush();
  1903.     gui_update_cursor(TRUE, FALSE);
  1904.     gui_mch_flush();
  1905.     /* Quit a hit-return or more prompt. */
  1906.     if (State == HITRETURN || State == ASKMORE)
  1907.     {
  1908.         add_to_input_buf((char_u *)"\003", 1);
  1909. #ifdef FEAT_GUI_GTK
  1910.         if (gtk_main_level() > 0)
  1911.         gtk_main_quit();
  1912. #endif
  1913.     }
  1914.     }
  1915.  
  1916.     return retval;
  1917. }
  1918.  
  1919.  
  1920. /*
  1921.  * Process a vim colon command.
  1922.  */
  1923.     static void
  1924. coloncmd(char *cmd, ...)
  1925. {
  1926.     char buf[1024];
  1927.     va_list ap;
  1928.  
  1929.     va_start(ap, cmd);
  1930.     vsprintf(buf, cmd, ap);
  1931.     va_end(ap);
  1932.  
  1933.     nbdebug(("    COLONCMD %s\n", buf));
  1934.  
  1935. /*     ALT_INPUT_LOCK_ON; */
  1936.     do_cmdline((char_u *)buf, NULL, NULL, DOCMD_NOWAIT | DOCMD_KEYTYPED);
  1937. /*     ALT_INPUT_LOCK_OFF; */
  1938.  
  1939.     setcursor();        /* restore the cursor position */
  1940.     out_flush();        /* make sure output has been written */
  1941.  
  1942.     gui_update_cursor(TRUE, FALSE);
  1943.     gui_mch_flush();
  1944. }
  1945.  
  1946. #ifdef HAVE_READLINK
  1947.  
  1948. /*
  1949.  * Check symlinks for infinite recursion.
  1950.  * "level" is for recursion control.
  1951.  */
  1952.     static void
  1953. resolve_symlinks(char *filename, int level)
  1954. {
  1955.     struct stat sbuf;
  1956.  
  1957.     if ((level > 0) && (lstat(filename, &sbuf) == 0) && (S_ISLNK(sbuf.st_mode)))
  1958.     {
  1959.     char buf[MAXPATHLEN+1];
  1960.     int len = readlink(filename, buf, MAXPATHLEN);
  1961.  
  1962.     if (len < 0 || len == MAXPATHLEN)
  1963.     {
  1964.         EMSGN("E652: readlink() failed, errno = %ld\n", errno);
  1965.     }
  1966.     else
  1967.     {
  1968.         buf[len] = '\0';
  1969.  
  1970.         if (buf[0] == '/')
  1971.         {
  1972.         /* link value is absolute */
  1973.         strcpy(filename, buf);
  1974.         }
  1975.         else
  1976.         {
  1977.         /* link is relative */
  1978.         char *p = strrchr(filename, '/');
  1979.  
  1980.         if (p == 0)
  1981.             EMSG("E653: missing slash!?!");
  1982.         else
  1983.             if ((p - filename) + strlen(buf) > MAXPATHLEN)
  1984.             EMSG("E654: buffer overflow in resolve_symlinks()");
  1985.             else
  1986.             strcpy(p+1, buf);
  1987.         }
  1988.  
  1989.         /* check for symlinks in resulting path */
  1990.         resolve_symlinks(filename, level-1);
  1991.     }
  1992.     }
  1993. }
  1994.  
  1995. #endif /* HAVE_READLINK */
  1996.  
  1997. static char *rundir = "";
  1998.  
  1999. /*
  2000.  * Set rundir -- Dynamically find VIMRUNTIME dir
  2001.  */
  2002.     void
  2003. netbeans_setRunDir(char *argv0)
  2004. {
  2005.     char    fullpath[MAXPATHLEN];
  2006.     char    *p;
  2007.     static char buf[MAXPATHLEN];
  2008.  
  2009.     if (*argv0 == '/')
  2010.     strcpy(fullpath, argv0);
  2011.     else if (strchr(argv0, '/'))
  2012.     {
  2013.     getcwd(fullpath, MAXPATHLEN);
  2014.     strcat(fullpath, "/");
  2015.     strcat(fullpath, argv0);
  2016.     }
  2017.     else /* no slash, have to search path */
  2018.     {
  2019.     char *path = getenv("PATH");
  2020.     if (path)
  2021.     {
  2022.         char *pathbuf = (char *)vim_strsave((char_u *)path);
  2023.         path = strtok(pathbuf, ":");
  2024.         do
  2025.         {
  2026.         strcpy(fullpath, path);
  2027.         strcat(fullpath, "/");
  2028.         strcat(fullpath, argv0);
  2029.         if (access(fullpath, X_OK) == 0)
  2030.             break;
  2031.         else
  2032.             fullpath[0] = NUL;
  2033.         } while ((path=strtok(NULL, ":")) != NULL);
  2034.         vim_free(pathbuf);
  2035.     }
  2036.     }
  2037.  
  2038. #ifdef HAVE_READLINK
  2039.     /* resolve symlinks to get "real" base dir */
  2040.     resolve_symlinks(fullpath, 1000);
  2041. #endif /* HAVE_READLINK */
  2042.  
  2043.     /* search backwards for "bin" or "src" dir in fullpath */
  2044.  
  2045.     if (fullpath[0] != NUL)
  2046.     {
  2047.     p = strrchr(fullpath, '/');
  2048.     while (p)
  2049.     {
  2050.         if (strncmp(p, "/bin", 4) == 0 || strncmp(p, "/src", 4) == 0)
  2051.         {
  2052.         /* vim is in /.../bin  or /.../src */
  2053.         rundir = (char *)vim_strsave((char_u *)fullpath);
  2054.         break;
  2055.         }
  2056.         *p = NUL;
  2057.         p = strrchr(fullpath, '/');
  2058.     }
  2059.     }
  2060.  
  2061.     /* now find "doc" dir from the rundir (if $VIMRUNTIME is not set) */
  2062.  
  2063.     if ((p = getenv("VIMRUNTIME")) != NULL && *p != NUL)
  2064.     return;
  2065.  
  2066.     strcpy(buf, rundir);
  2067.     strcat(buf, "/../share/vim/");
  2068.     strcat(buf, "vim61/doc");
  2069.     if (access(buf, R_OK) < 0)
  2070.     {
  2071.     strcpy(buf, rundir);
  2072.     strcat(buf, "/../runtime/doc");
  2073.     if (access(buf, R_OK) < 0)
  2074.     {
  2075.         /* not found! */
  2076.         return;
  2077.     }
  2078.     else
  2079.     {
  2080.         strcpy(buf, rundir);
  2081.         strcat(buf, "/../runtime");
  2082.     }
  2083.     }
  2084.     else
  2085.     {
  2086.     strcpy(buf, rundir);
  2087.     strcat(buf, "/../share/vim/vim61");
  2088.     }
  2089.     default_vimruntime_dir = (char_u *)buf;
  2090. }
  2091.  
  2092. /*
  2093.  * Initialize highlights and signs for use by netbeans  (mostly obsolete)
  2094.  */
  2095.     static void
  2096. nb_init_graphics(void)
  2097. {
  2098.     static int did_init = FALSE;
  2099.  
  2100.     if (!did_init)
  2101.     {
  2102.     coloncmd(":highlight NBGuarded guibg=Cyan guifg=Black");
  2103.     coloncmd(":sign define %d linehl=NBGuarded", GUARDED);
  2104.  
  2105.     did_init = TRUE;
  2106.     }
  2107. }
  2108.  
  2109. /*
  2110.  * Convert key to netbeans name.
  2111.  */
  2112.     static void
  2113. netbeans_keyname(int key, char *buf)
  2114. {
  2115.     char *name = 0;
  2116.     char namebuf[2];
  2117.     int ctrl  = 0;
  2118.     int shift = 0;
  2119.     int alt   = 0;
  2120.  
  2121.     if (mod_mask & MOD_MASK_CTRL)
  2122.     ctrl = 1;
  2123.     if (mod_mask & MOD_MASK_SHIFT)
  2124.     shift = 1;
  2125.     if (mod_mask & MOD_MASK_ALT)
  2126.     alt = 1;
  2127.  
  2128.  
  2129.     switch (key)
  2130.     {
  2131.     case K_F1:        name = "F1";        break;
  2132.     case K_S_F1:    name = "F1";    shift = 1;    break;
  2133.     case K_F2:        name = "F2";        break;
  2134.     case K_S_F2:    name = "F2";    shift = 1;    break;
  2135.     case K_F3:        name = "F3";        break;
  2136.     case K_S_F3:    name = "F3";    shift = 1;    break;
  2137.     case K_F4:        name = "F4";        break;
  2138.     case K_S_F4:    name = "F4";    shift = 1;    break;
  2139.     case K_F5:        name = "F5";        break;
  2140.     case K_S_F5:    name = "F5";    shift = 1;    break;
  2141.     case K_F6:        name = "F6";        break;
  2142.     case K_S_F6:    name = "F6";    shift = 1;    break;
  2143.     case K_F7:        name = "F7";        break;
  2144.     case K_S_F7:    name = "F7";    shift = 1;    break;
  2145.     case K_F8:        name = "F8";        break;
  2146.     case K_S_F8:    name = "F8";    shift = 1;    break;
  2147.     case K_F9:        name = "F9";        break;
  2148.     case K_S_F9:    name = "F9";    shift = 1;    break;
  2149.     case K_F10:        name = "F10";        break;
  2150.     case K_S_F10:    name = "F10";    shift = 1;    break;
  2151.     case K_F11:        name = "F11";        break;
  2152.     case K_S_F11:    name = "F11";    shift = 1;    break;
  2153.     case K_F12:        name = "F12";        break;
  2154.     case K_S_F12:    name = "F12";    shift = 1;    break;
  2155.     default:
  2156.             if (key >= ' ' && key <= '~')
  2157.             {
  2158.                 /* Allow ASCII characters. */
  2159.                 name = namebuf;
  2160.                 namebuf[0] = key;
  2161.                 namebuf[1] = NUL;
  2162.             }
  2163.             else
  2164.                 name = "X";
  2165.             break;
  2166.     }
  2167.  
  2168.     buf[0] = '\0';
  2169.     if (ctrl)
  2170.     strcat(buf, "C");
  2171.     if (shift)
  2172.     strcat(buf, "S");
  2173.     if (alt)
  2174.     strcat(buf, "M"); /* META */
  2175.     if (ctrl || shift || alt)
  2176.     strcat(buf, "-");
  2177.     strcat(buf, name);
  2178. }
  2179.  
  2180. #ifdef FEAT_BEVAL
  2181. /*
  2182.  * Function to be called for balloon evaluation.  Grabs the text under the
  2183.  * cursor and sends it to the debugger for evaluation.  The debugger should
  2184.  * respond with a showBalloon command when there is a useful result.
  2185.  */
  2186. /*ARGSUSED*/
  2187.     static void
  2188. netbeans_beval_cb(
  2189.     BalloonEval    *beval,
  2190.     int         state)
  2191. {
  2192.     char_u    *filename;
  2193.     char_u    *text;
  2194.     int        line;
  2195.     int        col;
  2196.     char    buf[MAXPATHLEN * 2 + 25];
  2197.     char_u    *p;
  2198.  
  2199.     /* Don't do anything when 'ballooneval' is off, messages scrolled the
  2200.      * windows up or we have no connection. */
  2201.     if (!p_beval || msg_scrolled > 0 || !haveConnection)
  2202.     return;
  2203.  
  2204.     if (gui_mch_get_beval_info(beval, &filename, &line, &text, &col) == OK)
  2205.     {
  2206.     /* Send debugger request.  Only when the text is of reasonable
  2207.      * length. */
  2208.     if (text != NULL && text[0] != NUL && STRLEN(text) < MAXPATHLEN)
  2209.     {
  2210.         p = nb_quote(text);
  2211.         if (p != NULL)
  2212.         sprintf(buf, "0:balloonText=%d \"%s\"\n", cmdno, p);
  2213.         vim_free(p);
  2214.         nbdebug(("EVT: %s", buf));
  2215.         nb_send(buf, "netbeans_beval_cb");
  2216.     }
  2217.     vim_free(text);
  2218.     }
  2219. }
  2220. #endif
  2221.  
  2222. /*
  2223.  * Tell netbeans that the window was opened, ready for commands.
  2224.  */
  2225.     void
  2226. netbeans_startup_done(void)
  2227. {
  2228.     char *cmd = "0:startupDone=0\n";
  2229.  
  2230.     if (!haveConnection)
  2231.     return;
  2232.  
  2233.     nbdebug(("EVT: %s", cmd));
  2234.     nb_send(cmd, "netbeans_startup_done");
  2235.  
  2236. # if defined(FEAT_BEVAL) && defined(FEAT_GUI_MOTIF)
  2237.     if (gui.in_use)
  2238.     {
  2239.     /*
  2240.      * Set up the Balloon Expression Evaluation area for Motif.
  2241.      * GTK can do it earlier...
  2242.      * Always create it but disable it when 'ballooneval' isn't set.
  2243.      */
  2244.     balloonEval = gui_mch_create_beval_area(textArea, NULL,
  2245.                             &netbeans_beval_cb, NULL);
  2246.     if (!p_beval)
  2247.         gui_mch_disable_beval_area(balloonEval);
  2248.     }
  2249. # endif
  2250. }
  2251.  
  2252. #if defined(FEAT_GUI_MOTIF) || defined(PROTO)
  2253. /*
  2254.  * Tell netbeans that the window was moved or resized.
  2255.  */
  2256.     void
  2257. netbeans_frame_moved(int new_x, int new_y)
  2258. {
  2259.     char buf[128];
  2260.  
  2261.     if (!haveConnection)
  2262.     return;
  2263.  
  2264.     sprintf(buf, "0:geometry=%d %d %d %d %d\n",
  2265.             cmdno, (int)Columns, (int)Rows, new_x, new_y);
  2266.     nbdebug(("EVT: %s", buf));
  2267.     nb_send(buf, "netbeans_frame_moved");
  2268. }
  2269. #endif
  2270.  
  2271. /*
  2272.  * Tell netbeans the user opened a file.
  2273.  */
  2274.     void
  2275. netbeans_file_opened(char *filename)
  2276. {
  2277.     char buffer[2*MAXPATHLEN];
  2278.  
  2279.     if (!haveConnection)
  2280.     return;
  2281.  
  2282.     sprintf(buffer, "0:fileOpened=%d \"%s\" %s %s\n",
  2283.         0,
  2284.         filename,
  2285.         "F",  /* open in NetBeans */
  2286.         "F"); /* modified */
  2287.  
  2288.     nbdebug(("EVT: %s", buffer));
  2289.  
  2290.     nb_send(buffer, "netbeans_file_opened");
  2291.     if (p_acd && vim_chdirfile((char_u *)filename) == OK)
  2292.     shorten_fnames(TRUE);
  2293. }
  2294.  
  2295. /*
  2296.  * Tell netbeans a file was closed.
  2297.  */
  2298.     void
  2299. netbeans_file_closed(buf_T *bufp)
  2300. {
  2301.     int        bufno = nb_getbufno(bufp);
  2302.     nbbuf_T    *nbbuf = nb_get_buf(bufno);
  2303.     char    buffer[2*MAXPATHLEN];
  2304.  
  2305.     if (!haveConnection)
  2306.     return;
  2307.  
  2308.     if (!netbeansCloseFile)
  2309.     {
  2310.     nbdebug(("ignoring file_closed for %s\n", bufp->b_ffname));
  2311.     return;
  2312.     }
  2313.  
  2314.     nbdebug(("netbeans_file_closed() bufno =  %d, file = %s, displayname = %s\n",
  2315.         bufno, bufp->b_ffname,
  2316.         (nbbuf != NULL) ? nbbuf->displayname : "<>"));
  2317.  
  2318.     if (bufno <= 0)
  2319.     return;
  2320.  
  2321.     sprintf(buffer, "%d:killed=%d\n", bufno, cmdno);
  2322.  
  2323.     nbdebug(("EVT: %s", buffer));
  2324.  
  2325.     nb_send(buffer, "netbeans_file_closed");
  2326.  
  2327.     if (nbbuf != NULL)
  2328.     nbbuf->bufp = NULL;
  2329. }
  2330.  
  2331. /*
  2332.  * Get a pointer to the Netbeans buffer for Vim buffer "bufp".
  2333.  * Return NULL if there is no such buffer or changes are not to be reported.
  2334.  * Otherwise store the buffer number in "*bufnop".
  2335.  */
  2336.     static nbbuf_T *
  2337. nb_bufp2nbbuf_fire(buf_T *bufp, int *bufnop)
  2338. {
  2339.     int        bufno;
  2340.     nbbuf_T    *nbbuf;
  2341.  
  2342.     if (!haveConnection || !netbeansFireChanges)
  2343.     return NULL;        /* changes are not reported at all */
  2344.  
  2345.     bufno = nb_getbufno(bufp);
  2346.     if (bufno <= 0)
  2347.     return NULL;        /* file is not known to NetBeans */
  2348.  
  2349.     nbbuf = nb_get_buf(bufno);
  2350.     if (nbbuf != NULL && !nbbuf->fireChanges)
  2351.     return NULL;        /* changes in this buffer are not reported */
  2352.  
  2353.     *bufnop = bufno;
  2354.     return nbbuf;
  2355. }
  2356.  
  2357. /*
  2358.  * Tell netbeans the user inserted some text.
  2359.  */
  2360.     void
  2361. netbeans_inserted(
  2362.     buf_T    *bufp,
  2363.     linenr_T    linenr,
  2364.     colnr_T    col,
  2365.     int        oldlen,
  2366.     char_u    *txt,
  2367.     int        newlen)
  2368. {
  2369.     char_u    *buf;
  2370.     int        bufno;
  2371.     nbbuf_T    *nbbuf;
  2372.     pos_T    pos;
  2373.     long    off;
  2374.     char_u    *p;
  2375.     char_u    *newtxt;
  2376.  
  2377.     nbbuf = nb_bufp2nbbuf_fire(bufp, &bufno);
  2378.     if (nbbuf == NULL)
  2379.     return;
  2380.  
  2381.     nbbuf->modified = 1;
  2382.  
  2383.     pos.lnum = linenr;
  2384.     pos.col = col;
  2385.  
  2386.     off = pos2off(bufp, &pos);
  2387.  
  2388. /*     nbdebug(("linenr = %d, col = %d, off = %ld\n", linenr, col, off)); */
  2389.  
  2390.     buf = alloc(128 + 2*newlen);
  2391.  
  2392.     if (oldlen > 0)
  2393.     {
  2394.     /* some chars were replaced; send "remove" EVT */
  2395.     sprintf((char *)buf, "%d:remove=%d %ld %d\n",
  2396.                            bufno, cmdno, off, oldlen);
  2397.     nbdebug(("EVT: %s", buf));
  2398.     nb_send((char *)buf, "netbeans_inserted");
  2399.     }
  2400.     else if (oldlen < 0)
  2401.     {
  2402.     /* can't happen? */
  2403.     nbdebug(("unexpected: oldlen < 0 in netbeans_inserted"));
  2404.     }
  2405.  
  2406.     /* send the "insert" EVT */
  2407.     newtxt = alloc(newlen + 1);
  2408.     STRNCPY(newtxt, txt, newlen);
  2409.     newtxt[newlen] = '\0';
  2410.     p = nb_quote(newtxt);
  2411.     if (p != NULL)
  2412.     sprintf((char *)buf, "%d:insert=%d %ld \"%s\"\n", bufno, cmdno, off, p);
  2413.     vim_free(p);
  2414.     vim_free(newtxt);
  2415.     nbdebug(("EVT: %s", buf));
  2416.     nb_send((char *)buf, "netbeans_inserted");
  2417.     vim_free(buf);
  2418. }
  2419.  
  2420. /*
  2421.  * Tell netbeans some bytes have been removed.
  2422.  */
  2423.     void
  2424. netbeans_removed(
  2425.     buf_T    *bufp,
  2426.     linenr_T    linenr,
  2427.     colnr_T    col,
  2428.     long    len)
  2429. {
  2430.     char_u    buf[128];
  2431.     int        bufno;
  2432.     nbbuf_T    *nbbuf;
  2433.     pos_T    pos;
  2434.     long    off;
  2435.  
  2436.     nbbuf = nb_bufp2nbbuf_fire(bufp, &bufno);
  2437.     if (nbbuf == NULL)
  2438.     return;
  2439.  
  2440.     if (len < 0)
  2441.     {
  2442.     nbdebug(("Negative len %ld in netbeans_removed()!", len));
  2443.     return;
  2444.     }
  2445.  
  2446.     nbbuf->modified = 1;
  2447.  
  2448.     pos.lnum = linenr;
  2449.     pos.col = col;
  2450.  
  2451.     off = pos2off(bufp, &pos);
  2452.  
  2453.     sprintf((char *)buf, "%d:remove=%d %ld %ld\n", bufno, cmdno, off, len);
  2454.     nbdebug(("EVT: %s", buf));
  2455.     nb_send((char *)buf, "netbeans_removed");
  2456. }
  2457.  
  2458. /*
  2459.  * Send netbeans an unmodufied command.
  2460.  */
  2461.     void
  2462. netbeans_unmodified(buf_T *bufp)
  2463. {
  2464.     char_u    buf[128];
  2465.     int        bufno;
  2466.     nbbuf_T    *nbbuf;
  2467.  
  2468.     nbbuf = nb_bufp2nbbuf_fire(bufp, &bufno);
  2469.     if (nbbuf == NULL)
  2470.     return;
  2471.  
  2472.     nbbuf->modified = 0;
  2473.  
  2474.     sprintf((char *)buf, "%d:unmodified=%d\n", bufno, cmdno);
  2475.     nbdebug(("EVT: %s", buf));
  2476.     nb_send((char *)buf, "netbeans_unmodified");
  2477. }
  2478.  
  2479. /*
  2480.  * Send a keypress event back to netbeans. This usualy simulates some
  2481.  * kind of function key press.
  2482.  */
  2483.     void
  2484. netbeans_keycommand(int key)
  2485. {
  2486.     char    buf[2*MAXPATHLEN];
  2487.     int        bufno;
  2488.     char    keyName[60];
  2489.     long    off;
  2490.  
  2491.     if (!haveConnection)
  2492.     return;
  2493.  
  2494.     /* convert key to netbeans name */
  2495.     netbeans_keyname(key, keyName);
  2496.  
  2497.     bufno = nb_getbufno(curbuf);
  2498.  
  2499.     if (bufno == -1)
  2500.     {
  2501.     nbdebug(("got keycommand for non-NetBeans buffer, opening...\n"));
  2502.     sprintf(buf, "0:fileOpened=%d \"%s\" %s %s\n", 0, curbuf->b_ffname,
  2503.         "T",  /* open in NetBeans */
  2504.         "F"); /* modified */
  2505.     nbdebug(("EVT: %s", buf));
  2506.     nb_send(buf, "netbeans_keycommand");
  2507.  
  2508.     postpone_keycommand(key);
  2509.     return;
  2510.     }
  2511.  
  2512.     /* sync the cursor position */
  2513.     off = pos2off(curbuf, &curwin->w_cursor);
  2514.     sprintf(buf, "%d:newDotAndMark=%d %ld %ld\n", bufno, cmdno, off, off);
  2515.     nbdebug(("EVT: %s", buf));
  2516.     nb_send(buf, "netbeans_keycommand");
  2517.  
  2518.     /* now send keyCommand event */
  2519.     sprintf(buf, "%d:keyCommand=%d \"%s\"\n", bufno, cmdno, keyName);
  2520.     nbdebug(("EVT: %s", buf));
  2521.     nb_send(buf, "netbeans_keycommand");
  2522.  
  2523.     /* New: do both at once and include the lnum/col. */
  2524.     sprintf(buf, "%d:keyAtPos=%d \"%s\" %ld %ld/%ld\n", bufno, cmdno, keyName,
  2525.         off, (long)curwin->w_cursor.lnum, (long)curwin->w_cursor.col);
  2526.     nbdebug(("EVT: %s", buf));
  2527.     nb_send(buf, "netbeans_keycommand");
  2528. }
  2529.  
  2530.  
  2531. /*
  2532.  * Send a save event to netbeans.
  2533.  */
  2534.     void
  2535. netbeans_saved(buf_T *bufp)
  2536. {
  2537.     char_u    buf[64];
  2538.     int        bufno;
  2539.     nbbuf_T    *nbbuf;
  2540.  
  2541.     nbbuf = nb_bufp2nbbuf_fire(bufp, &bufno);
  2542.     if (nbbuf == NULL)
  2543.     return;
  2544.  
  2545.     nbbuf->modified = 0;
  2546.  
  2547.     sprintf((char *)buf, "%d:save=%d\n", bufno, cmdno);
  2548.     nbdebug(("EVT: %s", buf));
  2549.     nb_send((char *)buf, "netbeans_saved");
  2550. }
  2551.  
  2552.  
  2553. /*
  2554.  * Send remove command to netbeans (this command has been turned off).
  2555.  */
  2556.     void
  2557. netbeans_deleted_all_lines(buf_T *bufp)
  2558. {
  2559.     char_u    buf[64];
  2560.     int        bufno;
  2561.     nbbuf_T    *nbbuf;
  2562.  
  2563.     nbbuf = nb_bufp2nbbuf_fire(bufp, &bufno);
  2564.     if (nbbuf == NULL)
  2565.     return;
  2566.  
  2567.     nbbuf->modified = 1;
  2568.  
  2569.     sprintf((char *)buf, "%d:remove=%d 0 -1\n", bufno, cmdno);
  2570.     nbdebug(("EVT(suppressed): %s", buf));
  2571. /*     nb_send(buf, "netbeans_deleted_all_lines"); */
  2572. }
  2573.  
  2574.  
  2575. /*
  2576.  * See if the lines are guarded. The top and bot parameters are from
  2577.  * u_savecommon(), these are the line above the change and the line below the
  2578.  * change.
  2579.  */
  2580.     int
  2581. netbeans_is_guarded(linenr_T top, linenr_T bot)
  2582. {
  2583.     signlist_T    *p;
  2584.     int        lnum;
  2585.  
  2586.     for (p = curbuf->b_signlist; p != NULL; p = p->next)
  2587.     if (p->id >= GUARDEDOFFSET)
  2588.         for (lnum = top + 1; lnum < bot; lnum++)
  2589.         if (lnum == p->lnum)
  2590.             return TRUE;
  2591.  
  2592.     return FALSE;
  2593. }
  2594.  
  2595. #if defined(FEAT_GUI_MOTIF) || defined(PROTO)
  2596. /*
  2597.  * We have multiple signs to draw at the same location. Draw the
  2598.  * multi-sign indicator instead. This is the Motif version.
  2599.  */
  2600.     void
  2601. netbeans_draw_multisign_indicator(int row)
  2602. {
  2603.     int i;
  2604.     int y;
  2605.     int x;
  2606.  
  2607.     x = 0;
  2608.     y = row * gui.char_height + 2;
  2609.  
  2610.     for (i = 0; i < gui.char_height - 3; i++)
  2611.     XDrawPoint(gui.dpy, gui.wid, gui.text_gc, x+2, y++);
  2612.  
  2613.     XDrawPoint(gui.dpy, gui.wid, gui.text_gc, x+0, y);
  2614.     XDrawPoint(gui.dpy, gui.wid, gui.text_gc, x+2, y);
  2615.     XDrawPoint(gui.dpy, gui.wid, gui.text_gc, x+4, y++);
  2616.     XDrawPoint(gui.dpy, gui.wid, gui.text_gc, x+1, y);
  2617.     XDrawPoint(gui.dpy, gui.wid, gui.text_gc, x+2, y);
  2618.     XDrawPoint(gui.dpy, gui.wid, gui.text_gc, x+3, y++);
  2619.     XDrawPoint(gui.dpy, gui.wid, gui.text_gc, x+2, y);
  2620. }
  2621. #endif /* FEAT_GUI_MOTIF */
  2622.  
  2623. #ifdef FEAT_GUI_GTK
  2624. /*
  2625.  * We have multiple signs to draw at the same location. Draw the
  2626.  * multi-sign indicator instead. This is the GTK/Gnome version.
  2627.  */
  2628.     void
  2629. netbeans_draw_multisign_indicator(int row)
  2630. {
  2631.     int i;
  2632.     int y;
  2633.     int x;
  2634.     GdkDrawable *drawable = gui.drawarea->window;
  2635.  
  2636.     x = 0;
  2637.     y = row * gui.char_height + 2;
  2638.  
  2639.     for (i = 0; i < gui.char_height - 3; i++)
  2640.     gdk_draw_point(drawable, gui.text_gc, x+2, y++);
  2641.  
  2642.     gdk_draw_point(drawable, gui.text_gc, x+0, y);
  2643.     gdk_draw_point(drawable, gui.text_gc, x+2, y);
  2644.     gdk_draw_point(drawable, gui.text_gc, x+4, y++);
  2645.     gdk_draw_point(drawable, gui.text_gc, x+1, y);
  2646.     gdk_draw_point(drawable, gui.text_gc, x+2, y);
  2647.     gdk_draw_point(drawable, gui.text_gc, x+3, y++);
  2648.     gdk_draw_point(drawable, gui.text_gc, x+2, y);
  2649. }
  2650. #endif /* FEAT_GUI_GTK */
  2651.  
  2652. /*
  2653.  * If the mouse is clicked in the gutter of a line with multiple
  2654.  * annotations, cycle through the set of signs.
  2655.  */
  2656.     void
  2657. netbeans_gutter_click(linenr_T lnum)
  2658. {
  2659.     signlist_T    *p;
  2660.  
  2661.     for (p = curbuf->b_signlist; p != NULL; p = p->next)
  2662.     {
  2663.     if (p->lnum == lnum && p->next && p->next->lnum == lnum)
  2664.     {
  2665.         signlist_T *tail;
  2666.  
  2667.         /* remove "p" from list, reinsert it at the tail of the sublist */
  2668.         if (p->prev)
  2669.         p->prev->next = p->next;
  2670.         else
  2671.         curbuf->b_signlist = p->next;
  2672.         p->next->prev = p->prev;
  2673.         /* now find end of sublist and insert p */
  2674.         for (tail = p->next;
  2675.           tail->next && tail->next->lnum == lnum
  2676.                         && tail->next->id < GUARDEDOFFSET;
  2677.           tail = tail->next)
  2678.         ;
  2679.         /* tail now points to last entry with same lnum (except
  2680.          * that "guarded" annotations are always last) */
  2681.         p->next = tail->next;
  2682.         if (tail->next)
  2683.         tail->next->prev = p;
  2684.         p->prev = tail;
  2685.         tail->next = p;
  2686.         update_debug_sign(curbuf, lnum);
  2687.         break;
  2688.     }
  2689.     }
  2690. }
  2691.  
  2692.  
  2693. /*
  2694.  * Add a sign of the reqested type at the requested location.
  2695.  *
  2696.  * Reverse engineering:
  2697.  * Apparently an annotation is defined the first time it is used in a buffer.
  2698.  * When the same annotation is used in two buffers, the second time we do not
  2699.  * need to define a new sign name but reuse the existing one.  But since the
  2700.  * ID number used in the second buffer starts counting at one again, a mapping
  2701.  * is made from the ID specifically for the buffer to the global sign name
  2702.  * (which is a number).
  2703.  *
  2704.  * globalsignmap[]    stores the signs that have been defined globally.
  2705.  * buf->signmapused[]    maps buffer-local annotation IDs to an index in
  2706.  *            globalsignmap[].
  2707.  */
  2708. /*ARGSUSED*/
  2709.     static void
  2710. addsigntype(
  2711.     nbbuf_T    *buf,
  2712.     int        typeNum,
  2713.     char_u    *typeName,
  2714.     char_u    *tooltip,
  2715.     char_u    *glyphFile,
  2716.     int        use_fg,
  2717.     int        fg,
  2718.     int        use_bg,
  2719.     int        bg)
  2720. {
  2721.     char fgbuf[32];
  2722.     char bgbuf[32];
  2723.     int i, j;
  2724.  
  2725.     for (i = 0; i < globalsignmapused; i++)
  2726.     if (STRCMP(typeName, globalsignmap[i]) == 0)
  2727.         break;
  2728.  
  2729.     if (i == globalsignmapused) /* not found; add it to global map */
  2730.     {
  2731.     nbdebug(("DEFINEANNOTYPE(%d,%s,%s,%s,%d,%d)\n",
  2732.                 typeNum, typeName, tooltip, glyphFile, fg, bg));
  2733.     if (use_fg || use_bg)
  2734.     {
  2735.         sprintf(fgbuf, "guifg=#%06x", fg & 0xFFFFFF);
  2736.         sprintf(bgbuf, "guibg=#%06x", bg & 0xFFFFFF);
  2737.  
  2738.         coloncmd(":highlight NB_%s %s %s", typeName, (use_fg) ? fgbuf : "",
  2739.              (use_bg) ? bgbuf : "");
  2740.         if (*glyphFile == NUL)
  2741.         /* no glyph, line highlighting only */
  2742.         coloncmd(":sign define %d linehl=NB_%s", i + 1, typeName);
  2743.         else if (vim_strsize(glyphFile) <= 2)
  2744.         /* one- or two-character glyph name, use as text glyph with
  2745.          * texthl */
  2746.         coloncmd(":sign define %d text=%s texthl=NB_%s", i + 1,
  2747.                              glyphFile, typeName);
  2748.         else
  2749.         /* glyph, line highlighting */
  2750.         coloncmd(":sign define %d icon=%s linehl=NB_%s", i + 1,
  2751.                              glyphFile, typeName);
  2752.     }
  2753.     else
  2754.         /* glyph, no line highlighting */
  2755.         coloncmd(":sign define %d icon=%s", i + 1, glyphFile);
  2756.  
  2757.     if (STRCMP(typeName,"CurrentPC") == 0)
  2758.         curPCtype = typeNum;
  2759.  
  2760.     if (globalsignmapused == globalsignmaplen)
  2761.     {
  2762.         if (globalsignmaplen == 0) /* first allocation */
  2763.         {
  2764.         globalsignmaplen = 20;
  2765.         globalsignmap = (char **)alloc_clear(globalsignmaplen*sizeof(char *));
  2766.         }
  2767.         else    /* grow it */
  2768.         {
  2769.         int incr;
  2770.         int oldlen = globalsignmaplen;
  2771.  
  2772.         globalsignmaplen *= 2;
  2773.         incr = globalsignmaplen - oldlen;
  2774.         globalsignmap = (char **)vim_realloc(globalsignmap,
  2775.                        globalsignmaplen * sizeof(char *));
  2776.         memset(globalsignmap + oldlen, 0, incr * sizeof(char *));
  2777.         }
  2778.     }
  2779.  
  2780.     globalsignmap[i] = (char *)typeName;
  2781.     globalsignmapused = i + 1;
  2782.     }
  2783.  
  2784.     /* check local map; should *not* be found! */
  2785.     for (j = 0; j < buf->signmapused; j++)
  2786.     if (buf->signmap[j] == i + 1)
  2787.         return;
  2788.  
  2789.     /* add to local map */
  2790.     if (buf->signmapused == buf->signmaplen)
  2791.     {
  2792.     if (buf->signmaplen == 0) /* first allocation */
  2793.     {
  2794.         buf->signmaplen = 5;
  2795.         buf->signmap = (int *)alloc_clear(buf->signmaplen * sizeof(int *));
  2796.     }
  2797.     else    /* grow it */
  2798.     {
  2799.         int incr;
  2800.         int oldlen = buf->signmaplen;
  2801.         buf->signmaplen *= 2;
  2802.         incr = buf->signmaplen - oldlen;
  2803.         buf->signmap = (int *)vim_realloc(buf->signmap,
  2804.                            buf->signmaplen*sizeof(int *));
  2805.         memset(buf->signmap + oldlen, 0, incr * sizeof(int *));
  2806.     }
  2807.     }
  2808.  
  2809.     buf->signmap[buf->signmapused++] = i + 1;
  2810.  
  2811. }
  2812.  
  2813.  
  2814. /*
  2815.  * See if we have the requested sign type in the buffer.
  2816.  */
  2817.     static int
  2818. mapsigntype(nbbuf_T *buf, int localsigntype)
  2819. {
  2820.     if (--localsigntype >= 0 && localsigntype < buf->signmapused)
  2821.     return buf->signmap[localsigntype];
  2822.  
  2823.     return 0;
  2824. }
  2825.  
  2826.  
  2827. /*
  2828.  * Compute length of buffer, don't print anything.
  2829.  */
  2830.     static long
  2831. get_buf_size(buf_T *bufp)
  2832. {
  2833.     linenr_T    lnum;
  2834.     long    char_count = 0;
  2835.     int        eol_size;
  2836.     long    last_check = 100000L;
  2837.  
  2838.     if (bufp->b_ml.ml_flags & ML_EMPTY)
  2839.     return 0;
  2840.     else
  2841.     {
  2842.     if (get_fileformat(bufp) == EOL_DOS)
  2843.         eol_size = 2;
  2844.     else
  2845.         eol_size = 1;
  2846.     for (lnum = 1; lnum <= bufp->b_ml.ml_line_count; ++lnum)
  2847.     {
  2848.         char_count += STRLEN(ml_get(lnum)) + eol_size;
  2849.         /* Check for a CTRL-C every 100000 characters */
  2850.         if (char_count > last_check)
  2851.         {
  2852.         ui_breakcheck();
  2853.         if (got_int)
  2854.             return char_count;
  2855.         last_check = char_count + 100000L;
  2856.         }
  2857.     }
  2858.     /* Correction for when last line doesn't have an EOL. */
  2859.     if (!bufp->b_p_eol && bufp->b_p_bin)
  2860.         char_count -= eol_size;
  2861.     }
  2862.  
  2863.     return char_count;
  2864. }
  2865.  
  2866. /*
  2867.  * Convert character offset to lnum,col
  2868.  */
  2869.     static pos_T *
  2870. off2pos(buf_T *buf, long offset)
  2871. {
  2872.     linenr_T     lnum;
  2873.     static pos_T pos;
  2874.  
  2875.     pos.lnum = 0;
  2876.     pos.col = 0;
  2877. #ifdef FEAT_VIRTUALEDIT
  2878.     pos.coladd = 0;
  2879. #endif
  2880.  
  2881.     if (!(buf->b_ml.ml_flags & ML_EMPTY))
  2882.     {
  2883.     if ((lnum = ml_find_line_or_offset(buf, (linenr_T)0, &offset)) < 0)
  2884.         return NULL;
  2885.     pos.lnum = lnum;
  2886.     pos.col = offset;
  2887.     }
  2888.  
  2889.     return &pos;
  2890. }
  2891.  
  2892. /*
  2893.  * Convert an argument in the form "1234" to an offset and compute the
  2894.  * lnum/col from it.  Convert an argument in the form "123/12" directly to a
  2895.  * lnum/col.
  2896.  * "argp" is advanced to after the argument.
  2897.  * Return a pointer to the position, NULL if something is wrong.
  2898.  */
  2899.     static pos_T *
  2900. get_off_or_lnum(buf_T *buf, char_u **argp)
  2901. {
  2902.     static pos_T    mypos;
  2903.     long        off;
  2904.  
  2905.     off = strtol((char *)*argp, (char **)argp, 10);
  2906.     if (**argp == '/')
  2907.     {
  2908.     mypos.lnum = (linenr_T)off;
  2909.     ++*argp;
  2910.     mypos.col = strtol((char *)*argp, (char **)argp, 10);
  2911. #ifdef FEAT_VIRTUALEDIT
  2912.     mypos.coladd = 0;
  2913. #endif
  2914.     return &mypos;
  2915.     }
  2916.     return off2pos(buf, off);
  2917. }
  2918.  
  2919.  
  2920. /*
  2921.  * Convert lnum,col to character offset
  2922.  */
  2923.     static long
  2924. pos2off(buf_T *buf, pos_T *pos)
  2925. {
  2926.     long     offset = 0;
  2927.  
  2928.     if (!(buf->b_ml.ml_flags & ML_EMPTY))
  2929.     {
  2930.     if ((offset = ml_find_line_or_offset(buf, pos->lnum, 0)) < 0)
  2931.         return 0;
  2932.     offset += pos->col;
  2933.     }
  2934.  
  2935.     return offset;
  2936. }
  2937.  
  2938.  
  2939. #if defined(FEAT_GUI_MOTIF) || defined(PROTO)
  2940. /*
  2941.  *    This function fills in the XRectangle object with the current
  2942.  *    x,y coordinates and height, width so that an XtVaSetValues to
  2943.  *    the same shell of those resources will restore the window to its
  2944.  *    formar position and dimensions.
  2945.  *
  2946.  *    Note: This function may fail, in which case the XRectangle will
  2947.  *    be unchanged.  Be sure to have the XRectangle set with the
  2948.  *    proper values for a failed condition prior to calling this
  2949.  *    function.
  2950.  */
  2951.     void
  2952. shellRectangle(Widget shell, XRectangle *r)
  2953. {
  2954.     Window        rootw, shellw, child, parentw;
  2955.     int        absx, absy;
  2956.     XWindowAttributes    a;
  2957.     Window        *children;
  2958.     unsigned int    childrenCount;
  2959.  
  2960.     shellw = XtWindow(shell);
  2961.     if (shellw == 0)
  2962.         return;
  2963.     for (;;)
  2964.     {
  2965.         XQueryTree(XtDisplay(shell), shellw, &rootw, &parentw,
  2966.                     &children, &childrenCount);
  2967.         XFree(children);
  2968.         if (parentw == rootw)
  2969.         break;
  2970.         shellw = parentw;
  2971.     }
  2972.     XGetWindowAttributes(XtDisplay(shell), shellw, &a);
  2973.     XTranslateCoordinates(XtDisplay(shell), shellw, a.root, 0, 0,
  2974.                 &absx, &absy, &child);
  2975.     r->x = absx;
  2976.     r->y = absy;
  2977.     XtVaGetValues(shell, XmNheight, &r->height,
  2978.                 XmNwidth, &r->width, NULL);
  2979. }
  2980. #endif
  2981.  
  2982. #endif /* defined(FEAT_NETBEANS_INTG) */
  2983.