tio.c

Go to the documentation of this file.
00001 /* tio.c */
00002 
00003 /* Author:
00004  *      Steve Kirkendall
00005  *      14407 SW Teal Blvd. #C
00006  *      Beaverton, OR 97005
00007  *      kirkenda@cs.pdx.edu
00008  */
00009 
00010 
00011 /* This file contains terminal I/O functions */
00012 
00013 #include "config.h"
00014 #include "vi.h"
00015 #include "ctype.h"
00016 
00017 
00018 /* This function reads in a line from the terminal. */
00019 int vgets(prompt, buf, bsize)
00020         char    prompt; /* the prompt character, or '\0' for none */
00021         char    *buf;   /* buffer into which the string is read */
00022         int     bsize;  /* size of the buffer */
00023 {
00024         int     len;    /* how much we've read so far */
00025         int     ch;     /* a character from the user */
00026         int     quoted; /* is the next char quoted? */
00027         int     tab;    /* column position of cursor */
00028         char    widths[132];    /* widths of characters */
00029         int     word;   /* index of first letter of word */
00030 #ifndef NO_DIGRAPH
00031         int     erased; /* 0, or first char of a digraph */
00032 #endif
00033 
00034         /* show the prompt */
00035         move(LINES - 1, 0);
00036         tab = 0;
00037         if (prompt)
00038         {
00039                 addch(prompt);
00040                 tab = 1;
00041         }
00042         clrtoeol();
00043         refresh();
00044 
00045         /* read in the line */
00046 #ifndef NO_DIGRAPH
00047         erased =
00048 #endif
00049         quoted = len = 0;
00050         for (;;)
00051         {
00052 #ifndef NO_ABBR
00053                 if (quoted || mode == MODE_EX)
00054                 {
00055                         ch = getkey(0);
00056                 }
00057                 else
00058                 {
00059                         /* maybe expand an abbreviation while getting key */
00060                         for (word = len; --word >= 0 && isalnum(buf[word]); )
00061                         {
00062                         }
00063                         word++;
00064                         ch = getabkey(WHEN_EX, &buf[word], len - word);
00065                 }
00066 #else
00067                 ch = getkey(0);
00068 #endif
00069 #ifndef NO_EXTENSIONS
00070                 if (ch == ctrl('O'))
00071                 {
00072                         ch = getkey(quoted ? 0 : WHEN_EX);
00073                 }
00074 #endif
00075 
00076                 /* some special conversions */
00077                 if (ch == ctrl('D') && len == 0)
00078                         ch = ctrl('[');
00079 #ifndef NO_DIGRAPH
00080                 if (*o_digraph && erased != 0 && ch != '\b')
00081                 {
00082                         ch = digraph(erased, ch);
00083                         erased = 0;
00084                 }
00085 #endif
00086 
00087                 /* inhibit detection of special chars (except ^J) after a ^V */
00088                 if (quoted && ch != '\n')
00089                 {
00090                         ch |= 256;
00091                 }
00092 
00093                 /* process the character */
00094                 switch(ch)
00095                 {
00096                   case ctrl('V'):
00097                         qaddch('^');
00098                         qaddch('\b');
00099                         quoted = TRUE;
00100                         break;
00101 
00102                   case ctrl('['):
00103                         return -1;
00104 
00105                   case '\n':
00106 #if OSK
00107                   case '\l':
00108 #else
00109                   case '\r':
00110 #endif
00111                         clrtoeol();
00112                         goto BreakBreak;
00113 
00114                   case '\b':
00115                         if (len > 0)
00116                         {
00117                                 len--;
00118 #ifndef NO_DIGRAPH
00119                                 erased = buf[len];
00120 #endif
00121                                 for (ch = widths[len]; ch > 0; ch--)
00122                                         addch('\b');
00123                                 if (mode == MODE_EX)
00124                                 {
00125                                         clrtoeol();
00126                                 }
00127                                 tab -= widths[len];
00128                         }
00129                         else
00130                         {
00131                                 return -1;
00132                         }
00133                         break;
00134 
00135                   default:
00136                         /* strip off quotation bit */
00137                         if (ch & 256)
00138                         {
00139                                 ch &= ~256;
00140                                 qaddch(' ');
00141                                 qaddch('\b');
00142                         }
00143 
00144                         /* add & echo the char */
00145                         if (len < bsize - 1)
00146                         {
00147                                 if (ch == '\t' && !quoted)
00148                                 {
00149                                         widths[len] = *o_tabstop - (tab % *o_tabstop);
00150                                         addstr("        " + 8 - widths[len]);
00151                                         tab += widths[len];
00152                                 }
00153                                 else if (ch > 0 && ch < ' ') /* > 0 by GB */
00154                                 {
00155                                         addch('^');
00156                                         addch(ch + '@');
00157                                         widths[len] = 2;
00158                                         tab += 2;
00159                                 }
00160                                 else if (ch == '\177')
00161                                 {
00162                                         addch('^');
00163                                         addch('?');
00164                                         widths[len] = 2;
00165                                         tab += 2;
00166                                 }
00167                                 else
00168                                 {
00169                                         addch(ch);
00170                                         widths[len] = 1;
00171                                         tab++;
00172                                 }
00173                                 buf[len++] = ch;
00174                         }
00175                         else
00176                         {
00177                                 beep();
00178                         }
00179                         quoted = FALSE;
00180                 }
00181         }
00182 BreakBreak:
00183         refresh();
00184         buf[len] = '\0';
00185         return len;
00186 }
00187 
00188 
00189 static int      manymsgs; /* This variable keeps msgs from overwriting each other */
00190 static char     pmsg[80]; /* previous message (waiting to be displayed) */
00191 
00192 
00193 static int showmsg()
00194 {
00195         /* if there is no message to show, then don't */
00196         if (!manymsgs)
00197                 return FALSE;
00198 
00199         /* display the message */
00200         move(LINES - 1, 0);
00201         if (*pmsg)
00202         {
00203                 standout();
00204                 qaddch(' ');
00205                 qaddstr(pmsg);
00206                 qaddch(' ');
00207                 standend();
00208         }
00209         clrtoeol();
00210 
00211         manymsgs = FALSE;
00212         return TRUE;
00213 }
00214 
00215 
00216 void endmsgs()
00217 {
00218         if (manymsgs)
00219         {
00220                 showmsg();
00221                 addch('\n');
00222         }
00223 }
00224 
00225 /* Write a message in an appropriate way.  This should really be a varargs
00226  * function, but there is no such thing as vwprintw.  Hack!!!
00227  *
00228  * In MODE_EX or MODE_COLON, the message is written immediately, with a
00229  * newline at the end.
00230  *
00231  * In MODE_VI, the message is stored in a character buffer.  It is not
00232  * displayed until getkey() is called.  msg() will call getkey() itself,
00233  * if necessary, to prevent messages from being lost.
00234  *
00235  * msg("")              - clears the message line
00236  * msg("%s %d", ...)    - does a printf onto the message line
00237  */
00238 /*VARARGS1*/
00239 void msg(fmt, arg1, arg2, arg3, arg4, arg5, arg6, arg7)
00240         char    *fmt;
00241         long    arg1, arg2, arg3, arg4, arg5, arg6, arg7;
00242 {
00243         if (mode != MODE_VI)
00244         {
00245                 sprintf(pmsg, fmt, arg1, arg2, arg3, arg4, arg5, arg6, arg7);
00246                 qaddstr(pmsg);
00247                 addch('\n');
00248                 exrefresh();
00249         }
00250         else
00251         {
00252                 /* wait for keypress between consecutive msgs */
00253                 if (manymsgs)
00254                 {
00255                         getkey(WHEN_MSG);
00256                 }
00257 
00258                 /* real message */
00259                 sprintf(pmsg, fmt, arg1, arg2, arg3, arg4, arg5, arg6, arg7);
00260                 if (*fmt)
00261                 {
00262                         manymsgs = TRUE;
00263                 }
00264         }
00265 }
00266 
00267 
00268 /* This function calls refresh() if the option exrefresh is set */
00269 void exrefresh()
00270 {
00271         char    *scan;
00272 
00273         /* If this ex command wrote ANYTHING set exwrote so vi's  :  command
00274          * can tell that it must wait for a user keystroke before redrawing.
00275          */
00276         for (scan=kbuf; scan<stdscr; scan++)
00277                 if (*scan == '\n')
00278                         exwrote = TRUE;
00279 
00280         /* now we do the refresh thing */
00281         if (*o_exrefresh)
00282         {
00283                 refresh();
00284         }
00285         else
00286         {
00287                 wqrefresh();
00288         }
00289         if (mode != MODE_VI)
00290         {
00291                 manymsgs = FALSE;
00292         }
00293 }
00294 
00295 
00296 /* This structure is used to store maps and abbreviations.  The distinction
00297  * between them is that maps are stored in the list referenced by the "maps"
00298  * pointer, while abbreviations are referenced by the "abbrs" pointer.
00299  */
00300 typedef struct _map
00301 {
00302         struct _map     *next;  /* another abbreviation */
00303         short           len;    /* length of the "rawin" characters */
00304         short           flags;  /* various flags */
00305         char            *label; /* label of the map/abbr, or NULL */
00306         char            *rawin; /* the "rawin" characters */
00307         char            *cooked;/* the "cooked" characters */
00308 } MAP;
00309 
00310 static char     keybuf[KEYBUFSIZE];
00311 static int      cend;   /* end of input characters */
00312 static int      user;   /* from user through end are chars typed by user */
00313 static int      next;   /* index of the next character to be returned */
00314 static MAP      *match; /* the matching map, found by countmatch() */
00315 static MAP      *maps;  /* the map table */
00316 #ifndef NO_ABBR
00317 static MAP      *abbrs; /* the abbreviation table */
00318 #endif
00319 
00320 
00321 
00322 /* ring the terminal's bell */
00323 void beep()
00324 {
00325         /* do a visible/audible bell */
00326         if (*o_flash)
00327         {
00328                 do_VB();
00329                 refresh();
00330         }
00331         else if (*o_errorbells)
00332         {
00333                 ttywrite("\007", 1);
00334         }
00335 
00336         /* discard any buffered input, and abort macros */
00337         next = user = cend;
00338 }
00339 
00340 
00341 
00342 /* This function replaces a "rawin" character sequence with the "cooked" version,
00343  * by modifying the internal type-ahead buffer.
00344  */
00345 void execmap(rawlen, cookedstr, visual)
00346         int     rawlen;         /* length of rawin text -- string to delete */
00347         char    *cookedstr;     /* the cooked text -- string to insert */
00348         int     visual;         /* boolean -- chars to be executed in visual mode? */
00349 {
00350         int     cookedlen;
00351         char    *src, *dst;
00352         int     i;
00353 
00354         /* find the length of the cooked string */
00355         cookedlen = strlen(cookedstr);
00356 #ifndef NO_EXTENSIONS
00357         if (visual)
00358         {
00359                 cookedlen *= 2;
00360         }
00361 #endif
00362 
00363         /* if too big to fit in type-ahead buffer, then don't do it */
00364         if (cookedlen + (cend - next) - rawlen > KEYBUFSIZE)
00365         {
00366                 return;
00367         }
00368 
00369         /* shift to make room for cookedstr at the front of keybuf */
00370         src = &keybuf[next + rawlen];
00371         dst = &keybuf[cookedlen];
00372         i = cend - (next + rawlen);
00373         if (src >= dst)
00374         {
00375                 while (i-- > 0)
00376                 {
00377                         *dst++ = *src++;
00378                 }
00379         }
00380         else
00381         {
00382                 src += i;
00383                 dst += i;
00384                 while (i-- > 0)
00385                 {
00386                         *--dst = *--src;
00387                 }
00388         }
00389 
00390         /* insert cookedstr, and adjust offsets */
00391         cend += cookedlen - rawlen - next;
00392         user += cookedlen - rawlen - next;
00393         next = 0;
00394         for (dst = keybuf, src = cookedstr; *src; )
00395         {
00396 #ifndef NO_EXTENSIONS
00397                 if (visual)
00398                 {
00399                         *dst++ = ctrl('O');
00400                         cookedlen--;
00401                 }
00402 #endif
00403                 *dst++ = *src++;
00404         }
00405 
00406 #ifdef DEBUG2
00407         {
00408 #include <stdio.h>
00409                 FILE    *debout;
00410                 int             i;
00411 
00412                 debout = fopen("debug.out", "a");
00413                 fprintf(debout, "After execmap(%d, \"%s\", %d)...\n", rawlen, cookedstr, visual);
00414                 for (i = 0; i < cend; i++)
00415                 {
00416                         if (i == next) fprintf(debout, "(next)");
00417                         if (i == user) fprintf(debout, "(user)");
00418                         if (UCHAR(keybuf[i]) < ' ')
00419                                 fprintf(debout, "^%c", keybuf[i] ^ '@');
00420                         else
00421                                 fprintf(debout, "%c", keybuf[i]);
00422                 }
00423                 fprintf(debout, "(end)\n");
00424                 fclose(debout);
00425         }
00426 #endif
00427 }
00428 
00429 /* This function calls ttyread().  If necessary, it will also redraw the screen,
00430  * change the cursor shape, display the mode, and update the ruler.  If the
00431  * number of characters read is 0, and we didn't time-out, then it exits because
00432  * we've apparently reached the end of an EX script.
00433  */
00434 static int fillkeybuf(when, timeout)
00435         int     when;   /* mixture of WHEN_XXX flags */
00436         int     timeout;/* timeout in 1/10 second increments, or 0 */
00437 {
00438         int     nkeys;
00439 #ifndef NO_SHOWMODE
00440         static int      oldwhen;        /* "when" from last time */
00441         static int      oldleft;
00442         static long     oldtop;
00443         static long     oldnlines;
00444         char            *str;
00445 #endif
00446 #ifndef NO_CURSORSHAPE
00447         static int      oldcurs;
00448 #endif
00449 
00450 #ifdef DEBUG
00451         watch();
00452 #endif
00453 
00454 
00455 #ifndef NO_CURSORSHAPE
00456         /* make sure the cursor is the right shape */
00457         if (has_CQ)
00458         {
00459                 if (when != oldcurs)
00460                 {
00461                         switch (when)
00462                         {
00463                           case WHEN_EX:         do_CX();        break;
00464                           case WHEN_VICMD:      do_CV();        break;
00465                           case WHEN_VIINP:      do_CI();        break;
00466                           case WHEN_VIREP:      do_CR();        break;
00467                         }
00468                         oldcurs = when;
00469                 }
00470         }
00471 #endif
00472 
00473 #ifndef NO_SHOWMODE
00474         /* if "showmode" then say which mode we're in */
00475         if (*o_smd && (when & WHENMASK))
00476         {
00477                 /* redraw the screen before we check to see whether the
00478                  * "showmode" message needs to be redrawn.
00479                  */
00480                 redraw(cursor, !(when & WHEN_VICMD));
00481 
00482                 /* now the "topline" test should be valid */
00483                 if (when != oldwhen || topline != oldtop || leftcol != oldleft || nlines != oldnlines)
00484                 {
00485                         oldwhen = when;
00486                         oldtop = topline;
00487                         oldleft = leftcol;
00488                         oldnlines = nlines;
00489 
00490                         if (when & WHEN_VICMD)      str = "Command";
00491                         else if (when & WHEN_VIINP) str = " Input ";
00492                         else if (when & WHEN_VIREP) str = "Replace";
00493                         else if (when & WHEN_REP1)  str = " Rep 1 ";
00494                         else if (when & WHEN_CUT)   str = "BufName";
00495                         else if (when & WHEN_MARK)  str = "Mark AZ";
00496                         else if (when & WHEN_CHAR)  str = "Dest Ch";
00497                         else                        str = (char *)0;
00498 
00499                         if (str)
00500                         {
00501                                 move(LINES - 1, COLS - 10);
00502                                 standout();
00503                                 qaddstr(str);
00504                                 standend();
00505                         }
00506                 }
00507         }
00508 #endif
00509 
00510 #ifndef NO_EXTENSIONS
00511         /* maybe display the ruler */
00512         if (*o_ruler && (when & (WHEN_VICMD|WHEN_VIINP|WHEN_VIREP)))
00513         {
00514                 char    buf[20];
00515 
00516                 redraw(cursor, !(when & WHEN_VICMD));
00517                 pfetch(markline(cursor));
00518                 sprintf(buf, "%7ld,%-4d", markline(cursor), 1 + idx2col(cursor, ptext, when & (WHEN_VIINP|WHEN_VIREP)));
00519                 move(LINES - 1, COLS - 22);
00520                 addstr(buf);
00521         }
00522 #endif
00523 
00524         /* redraw, so the cursor is in the right place */
00525         if (when & WHENMASK)
00526         {
00527                 redraw(cursor, !(when & (WHENMASK & ~(WHEN_VIREP|WHEN_VIINP))));
00528         }
00529 
00530         /* Okay, now we can finally read the rawin keystrokes */
00531         refresh();
00532         nkeys = ttyread(keybuf + cend, sizeof keybuf - cend, timeout);
00533 
00534         /* if nkeys == 0 then we've reached EOF of an ex script. */
00535         if (nkeys == 0 && timeout == 0)
00536         {
00537                 tmpabort(TRUE);
00538                 move(LINES - 1, 0);
00539                 clrtoeol();
00540                 refresh();
00541                 endwin();
00542                 exit(1);
00543         }
00544 
00545         cend += nkeys;
00546         user += nkeys;
00547         return nkeys;
00548 }
00549 
00550 
00551 /* This function counts the number of maps that could match the characters
00552  * between &keybuf[next] and &keybuf[cend], including incomplete matches.
00553  * The longest comlete match is remembered via the "match" variable.
00554  */
00555 static int countmatch(when)
00556         int     when;   /* mixture of WHEN_XXX flags */
00557 {
00558         MAP     *map;
00559         int     count;
00560 
00561         /* clear the "match" variable */
00562         match = (MAP *)0;
00563 
00564         /* check every map */
00565         for (count = 0, map = maps; map; map = map->next)
00566         {
00567                 /* can't match if wrong mode */
00568                 if ((map->flags & when) == 0)
00569                 {
00570                         continue;
00571                 }
00572 
00573                 /* would this be a complete match? */
00574                 if (map->len <= cend - next)
00575                 {
00576                         /* Yes, it would be.  Now does it really match? */
00577                         if (!strncmp(map->rawin, &keybuf[next], map->len))
00578                         {
00579                                 count++;
00580 
00581                                 /* if this is the longest complete match,
00582                                  * then remember it.
00583                                  */
00584                                 if (!match || match->len < map->len)
00585                                 {
00586                                         match = map;
00587                                 }
00588                         }
00589                 }
00590                 else
00591                 {
00592                         /* No, it wouldn't.  But check for partial match */
00593                         if (!strncmp(map->rawin, &keybuf[next], cend - next))
00594                         {
00595                                 count++;
00596                         }
00597                 }
00598         }
00599         return count;
00600 }
00601 
00602 
00603 #ifndef NO_ABBR
00604 /* This function checks to see whether a word is an abbreviation.  If it is,
00605  * then an appropriate number of backspoace characters is inserted into the
00606  * type-ahead buffer, followed by the expanded form of the abbreviation.
00607  */
00608 static void expandabbr(word, wlen)
00609         char    *word;
00610         int     wlen;
00611 {
00612         MAP     *abbr;
00613 
00614         /* if the next character wouldn't end the word, then don't expand */
00615         if (isalnum(keybuf[next]) || keybuf[next] == ctrl('V'))
00616         {
00617                 return;
00618         }
00619 
00620         /* find the abbreviation, if any */
00621         for (abbr = abbrs;
00622              abbr && (abbr->len != wlen || strncmp(abbr->rawin, word, wlen));
00623              abbr = abbr->next)
00624         {
00625         }
00626 
00627         /* If an abbreviation was found, then expand it by inserting the long
00628          * version into the type-ahead buffer, and then inserting (in front of
00629          * the long version) enough backspaces to erase to the short version.
00630          */
00631         if (abbr)
00632         {
00633                 execmap(0, abbr->cooked, FALSE);
00634                 while (wlen > 15)
00635                 {
00636                         execmap(0, "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b", FALSE);
00637                         wlen -= 15;
00638                 }
00639                 if (wlen > 0)
00640                 {
00641                         execmap(0, "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b" + 15 - wlen, FALSE);
00642                 }
00643         }
00644 }
00645 #endif
00646 
00647 
00648 /* This function calls getabkey() without attempting to expand abbreviations */
00649 int getkey(when)
00650         int     when;   /* mixture of WHEN_XXX flags */
00651 {
00652         return getabkey(when, "", 0);
00653 }
00654 
00655 
00656 /* This is it.  This function returns keystrokes one-at-a-time, after mapping
00657  * and abbreviations have been taken into account.
00658  */
00659 int getabkey(when, word, wlen)
00660         int     when;   /* mixture of WHEN_XXX flags */
00661         char    *word;  /* a word that may need to be expanded as an abbr */
00662         int     wlen;   /* length of "word" -- since "word" might not have \0 */
00663 {
00664         int     matches;
00665 
00666         /* if this key is needed for delay between multiple error messages,
00667          * then reset the manymsgs flag and abort any mapped key sequence.
00668          */
00669         if (showmsg())
00670         {
00671                 if (when == WHEN_MSG)
00672                 {
00673 #ifndef CRUNCH
00674                         if (!*o_more)
00675                         {
00676                                 refresh();
00677                                 return ' ';
00678                         }
00679 #endif
00680                         qaddstr("[More...]");
00681                         refresh();
00682                         execmap(user, "", FALSE);
00683                 }
00684         }
00685 
00686 #ifdef DEBUG
00687         /* periodically check for screwed up internal tables */
00688         watch();
00689 #endif
00690 
00691         /* if buffer empty, read some characters without timeout */
00692         if (next >= cend)
00693         {
00694                 next = user = cend = 0;
00695                 fillkeybuf(when, 0);
00696         }
00697 
00698         /* try to map the key, unless already mapped and not ":set noremap" */
00699         if (next >= user || *o_remap)
00700         {
00701                 do
00702                 {
00703                         do
00704                         {
00705                                 matches = countmatch(when);
00706                         } while (matches > 1 && fillkeybuf(when, *o_keytime) > 0);
00707                         if (matches == 1)
00708                         {
00709                                 execmap(match->len, match->cooked,
00710                                         (match->flags & WHEN_INMV) != 0 
00711                                          && (when & (WHEN_VIINP|WHEN_VIREP)) != 0);
00712                         }
00713                 } while (*o_remap && matches == 1);
00714         }
00715 
00716 #ifndef NO_ABBR
00717         /* try to expand an abbreviation, except in visual command mode */
00718         if (wlen > 0 && (mode & (WHEN_EX|WHEN_VIINP|WHEN_VIREP)) != 0)
00719         {
00720                 expandabbr(word, wlen);
00721         }
00722 #endif
00723 
00724         /* ERASEKEY should always be mapped to '\b'. */
00725         if (keybuf[next] == ERASEKEY)
00726         {
00727                 keybuf[next] = '\b';
00728         }
00729 
00730         /* return the next key */
00731         return keybuf[next++];
00732 }
00733 
00734 /* This function maps or unmaps a key */
00735 void mapkey(rawin, cooked, when, name)
00736         char    *rawin; /* the input key sequence, before mapping */
00737         char    *cooked;/* after mapping -- or NULL to remove map */
00738         short   when;   /* bitmap of when mapping should happen */
00739         char    *name;  /* name of the key, NULL for no name, "abbr" for abbr */
00740 {
00741         MAP     **head; /* head of list of maps or abbreviations */
00742         MAP     *scan;  /* used for scanning through the list */
00743         MAP     *prev;  /* used during deletions */
00744 
00745         /* Is this a map or an abbreviation?  Choose the right list. */
00746 #ifndef NO_ABBR
00747         head = ((!name || strcmp(name, "abbr")) ? &maps : &abbrs);
00748 #else
00749         head = &maps;
00750 #endif
00751 
00752         /* try to find the map in the list */
00753         for (scan = *head, prev = (MAP *)0;
00754              scan && (strcmp(rawin, scan->rawin) ||
00755                 !(scan->flags & when & (WHEN_EX|WHEN_VICMD|WHEN_VIINP|WHEN_VIREP)));
00756              prev = scan, scan = scan->next)
00757         {
00758         }
00759 
00760         /* trying to map? (not unmap) */
00761         if (cooked && *cooked)
00762         {
00763                 /* if map starts with "visual ", then mark it as a visual map */
00764                 if (head == &maps && !strncmp(cooked, "visual ", 7))
00765                 {
00766                         cooked += 7;
00767                         when |= WHEN_INMV;
00768                 }
00769 
00770                 /* "visual" maps always work in input mode */
00771                 if (when & WHEN_INMV)
00772                 {
00773                         when |= WHEN_VIINP|WHEN_VIREP|WHEN_POPUP;
00774                 }
00775 
00776                 /* if not already in the list, then allocate a new structure */
00777                 if (!scan)
00778                 {
00779                         scan = (MAP *)malloc(sizeof(MAP));
00780                         scan->len = strlen(rawin);
00781                         scan->rawin = malloc(scan->len + 1);
00782                         strcpy(scan->rawin, rawin);
00783                         scan->flags = when;
00784                         scan->label = name;
00785                         if (*head)
00786                         {
00787                                 prev->next = scan;
00788                         }
00789                         else
00790                         {
00791                                 *head = scan;
00792                         }
00793                         scan->next = (MAP *)0;
00794                 }
00795                 else /* recycle old structure */
00796                 {
00797                         free(scan->cooked);
00798                 }
00799                 scan->cooked = malloc(strlen(cooked) + 1);
00800                 strcpy(scan->cooked, cooked);
00801         }
00802         else /* unmapping */
00803         {
00804                 /* if nothing to unmap, then exit silently */
00805                 if (!scan)
00806                 {
00807                         return;
00808                 }
00809 
00810                 /* unlink the structure from the list */
00811                 if (prev)
00812                 {
00813                         prev->next = scan->next;
00814                 }
00815                 else
00816                 {
00817                         *head = scan->next;
00818                 }
00819 
00820                 /* free it, and the strings that it refers to */
00821                 free(scan->rawin);
00822                 free(scan->cooked);
00823                 free(scan);
00824         }
00825 }
00826 
00827 
00828 /* This function returns a printable version of a string.  It uses tmpblk.c */
00829 char *printable(str)
00830         char    *str;   /* the string to convert */
00831 {
00832         char    *build; /* used for building the string */
00833 
00834         for (build = tmpblk.c; *str; str++)
00835         {
00836 #if AMIGA
00837                 if (*str == '\233')
00838                 {
00839                         *build++ = '<';
00840                         *build++ = 'C';
00841                         *build++ = 'S';
00842                         *build++ = 'I';
00843                         *build++ = '>';
00844                 } else 
00845 #endif
00846                 if (UCHAR(*str) < ' ' || *str == '\177')
00847                 {
00848                         *build++ = '^';
00849                         *build++ = *str ^ '@';
00850                 }
00851                 else
00852                 {
00853                         *build++ = *str;
00854                 }
00855         }
00856         *build = '\0';
00857         return tmpblk.c;
00858 }
00859 
00860 /* This function displays the contents of either the map table or the
00861  * abbreviation table.  User commands call this function as follows:
00862  *      :map    dumpkey(WHEN_VICMD, FALSE);
00863  *      :map!   dumpkey(WHEN_VIREP|WHEN_VIINP, FALSE);
00864  *      :abbr   dumpkey(WHEN_VIINP|WHEN_VIREP, TRUE);
00865  *      :abbr!  dumpkey(WHEN_EX|WHEN_VIINP|WHEN_VIREP, TRUE);
00866  */
00867 void dumpkey(when, abbr)
00868         int     when;   /* WHEN_XXXX of mappings to be dumped */
00869         int     abbr;   /* boolean: dump abbreviations instead of maps? */
00870 {
00871         MAP     *scan;
00872         char    *str;
00873         int     len;
00874 
00875 #ifndef NO_ABBR
00876         for (scan = (abbr ? abbrs : maps); scan; scan = scan->next)
00877 #else
00878         for (scan = maps; scan; scan = scan->next)
00879 #endif
00880         {
00881                 /* skip entries that don't match "when" */
00882                 if ((scan->flags & when) == 0)
00883                 {
00884                         continue;
00885                 }
00886 
00887                 /* dump the key label, if any */
00888                 if (!abbr)
00889                 {
00890                         len = 8;
00891                         if (scan->label)
00892                         {
00893                                 qaddstr(scan->label);
00894                                 len -= strlen(scan->label);
00895                         }
00896                         do
00897                         {
00898                                 qaddch(' ');
00899                         } while (len-- > 0);
00900                 }
00901 
00902                 /* dump the rawin version */
00903                 str = printable(scan->rawin);
00904                 qaddstr(str);
00905                 len = strlen(str);
00906                 do
00907                 {
00908                         qaddch(' ');
00909                 } while (len++ < 8);
00910                         
00911                 /* dump the mapped version */
00912 #ifndef NO_EXTENSIONS
00913                 if ((scan->flags & WHEN_INMV) && (when & (WHEN_VIINP|WHEN_VIREP)))
00914                 {
00915                         qaddstr("visual ");
00916                 }
00917 #endif
00918                 str = printable(scan->cooked);
00919                 qaddstr(str);
00920                 addch('\n');
00921                 exrefresh();
00922         }
00923 }
00924 
00925 #ifndef NO_MKEXRC
00926 
00927 static safequote(str)
00928         char    *str;
00929 {
00930         char    *build;
00931 
00932         build = tmpblk.c + strlen(tmpblk.c);
00933         while (*str)
00934         {
00935                 if (*str <= ' ' && *str >= 1 || *str == '|')
00936                 {
00937                         *build++ = ctrl('V');
00938                 }
00939                 *build++ = *str++;
00940         }
00941         *build = '\0';
00942 }
00943 
00944 /* This function saves the contents of either the map table or the
00945  * abbreviation table into a file.  Both the "bang" and "no bang" versions
00946  * are saved.
00947  *      :map    dumpkey(WHEN_VICMD, FALSE);
00948  *      :map!   dumpkey(WHEN_VIREP|WHEN_VIINP, FALSE);
00949  *      :abbr   dumpkey(WHEN_VIINP|WHEN_VIREP, TRUE);
00950  *      :abbr!  dumpkey(WHEN_EX|WHEN_VIINP|WHEN_VIREP, TRUE);
00951  */
00952 savemaps(fd, abbr)
00953         int     fd;     /* file descriptor of an open file to write to */
00954         int     abbr;   /* boolean: do abbr table? (else do map table) */
00955 {
00956         MAP     *scan;
00957         char    *str;
00958         int     bang;
00959         int     when;
00960         int     len;
00961 
00962 # ifndef NO_ABBR
00963         for (scan = (abbr ? abbrs : maps); scan; scan = scan->next)
00964 # else
00965         for (scan = maps; scan; scan = scan->next)
00966 # endif
00967         {
00968                 /* skip maps that have labels, except for function keys */
00969                 if (scan->label && *scan->label != '#')
00970                 {
00971                         continue;
00972                 }
00973 
00974                 for (bang = 0; bang < 2; bang++)
00975                 {
00976                         /* decide which "when" flags we want */
00977 # ifndef NO_ABBR
00978                         if (abbr)
00979                                 when = (bang ? WHEN_EX|WHEN_VIINP|WHEN_VIREP : WHEN_VIINP|WHEN_VIREP);
00980                         else
00981 # endif
00982                                 when = (bang ? WHEN_VIREP|WHEN_VIINP : WHEN_VICMD);
00983 
00984                         /* skip entries that don't match "when" */
00985                         if ((scan->flags & when) == 0)
00986                         {
00987                                 continue;
00988                         }
00989 
00990                         /* write a "map" or "abbr" command name */
00991 # ifndef NO_ABBR
00992                         if (abbr)
00993                                 strcpy(tmpblk.c, "abbr");
00994                         else
00995 # endif
00996                                 strcpy(tmpblk.c, "map");
00997 
00998                         /* maybe write a bang.  Definitely write a space */
00999                         if (bang)
01000                                 strcat(tmpblk.c, "! ");
01001                         else
01002                                 strcat(tmpblk.c, " ");
01003 
01004                         /* write the rawin version */
01005 # ifndef NO_FKEY
01006                         if (scan->label)
01007                                 strcat(tmpblk.c, scan->label);
01008                         else
01009 # endif
01010                                 safequote(scan->rawin);
01011                         strcat(tmpblk.c, " ");
01012                                 
01013                         /* dump the mapped version */
01014 # ifndef NO_EXTENSIONS
01015                         if ((scan->flags & WHEN_INMV) && (when & (WHEN_VIINP|WHEN_VIREP)))
01016                         {
01017                                 strcat(tmpblk.c, "visual ");
01018                         }
01019 # endif
01020                         safequote(scan->cooked);
01021                         strcat(tmpblk.c, "\n");
01022                         twrite(fd, tmpblk.c, strlen(tmpblk.c));
01023                 }
01024         }
01025 }
01026 #endif

Generated on Fri Apr 14 22:56:53 2006 for minix by  doxygen 1.4.6