Back to index

lightning-sunbird  0.9+nobinonly
ltermInput.c
Go to the documentation of this file.
00001 /* ***** BEGIN LICENSE BLOCK *****
00002  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00003  *
00004  * The contents of this file are subject to the Mozilla Public License Version
00005  * 1.1 (the "License"); you may not use this file except in compliance with
00006  * the License. You may obtain a copy of the License at
00007  * http://www.mozilla.org/MPL/
00008  *
00009  * Software distributed under the License is distributed on an "AS IS" basis,
00010  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00011  * for the specific language governing rights and limitations under the
00012  * License.
00013  *
00014  * The Original Code is lineterm.
00015  *
00016  * The Initial Developer of the Original Code is
00017  * Ramalingam Saravanan.
00018  * Portions created by the Initial Developer are Copyright (C) 1999
00019  * the Initial Developer. All Rights Reserved.
00020  *
00021  * Contributor(s):
00022  *
00023  * Alternatively, the contents of this file may be used under the terms of
00024  * either the GNU General Public License Version 2 or later (the "GPL"), or
00025  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00026  * in which case the provisions of the GPL or the LGPL are applicable instead
00027  * of those above. If you wish to allow use of your version of this file only
00028  * under the terms of either the GPL or the LGPL, and not to allow others to
00029  * use your version of this file under the terms of the MPL, indicate your
00030  * decision by deleting the provisions above and replace them with the notice
00031  * and other provisions required by the GPL or the LGPL. If you do not delete
00032  * the provisions above, a recipient may use your version of this file under
00033  * the terms of any one of the MPL, the GPL or the LGPL.
00034  *
00035  * ***** END LICENSE BLOCK ***** */
00036 
00037 /* ltermInput.c: LTERM PTY input data processing
00038  */
00039 
00040 /* public declarations */
00041 #include "lineterm.h"
00042 
00043 /* private declarations */
00044 #include "ltermPrivate.h"
00045 
00046 
00047 static int ltermLineInput(struct lterms *lts, const UNICHAR *buf, int count,
00048                           int *opcodes);
00049 static int ltermMetaInput(struct lterms *lts);
00050 static int ltermRequestCompletion(struct lterms *lts, UNICHAR uch);
00051 
00052 
00063 int ltermPlainTextInput(struct lterms *lts,
00064                         const UNICHAR *buf, int count, int *opcodes)
00065 {
00066   struct LtermInput *lti = &(lts->ltermInput);
00067   int returnCode;
00068 
00069   LTERM_LOG(ltermPlainTextInput,20,
00070     ("count=%d, lti->inputMode=%d\n", count, lti->inputMode));
00071 
00072   if (lti->inputMode == LTERM0_RAW_MODE) {
00073     /* Transmit characters immediately to child process; no buffering */
00074 
00075     LTERM_LOG(ltermPlainTextInput,29,
00076                                     ("Raw mode, transmitting %d characters\n",
00077                                      count));
00078 
00079     if (ltermSendData(lts, buf, count) != 0)
00080       return -1;
00081 
00082     *opcodes = 0;
00083 
00084   } else {
00085     /* Not raw input mode; process line mode input */
00086     int processTrailingTab = 0;
00087 
00088     LTERM_LOG(ltermPlainTextInput,21,
00089               ("Line mode, lts->commandNumber=%d, inputMode=%d\n",
00090                lts->commandNumber, lti->inputMode));
00091 
00092     if ((lti->inputMode >= LTERM3_COMPLETION_MODE) &&
00093         (lts->commandNumber == 0)) {
00094       /* Downgrade input mode */
00095       lti->inputMode = LTERM2_EDIT_MODE;
00096 
00097       LTERM_LOG(ltermPlainTextInput,21,
00098                 ("------------ Downgraded input mode=%d\n\n",
00099                  lti->inputMode));
00100 
00101     } else  if ((lti->inputMode < lts->maxInputMode) &&
00102                 (lts->commandNumber != 0)) {
00103       /* Upgrade input mode */
00104       int priorInputMode = lti->inputMode;
00105 
00106       /* Set input mode (possibly allowing completion) */
00107       lti->inputMode = lts->maxInputMode;
00108 
00109       /* Do not allow command completion without TTY echo */
00110       if ( (lts->disabledInputEcho || lts->noTTYEcho) &&
00111            (lti->inputMode > LTERM2_EDIT_MODE) )
00112         lti->inputMode = LTERM2_EDIT_MODE;
00113 
00114       if ((lti->inputChars > 0) &&
00115           (priorInputMode < LTERM3_COMPLETION_MODE) &&
00116           (lti->inputMode >= LTERM3_COMPLETION_MODE)) {
00117         /* Process prior input TABs before switching to completion mode */
00118         int j;
00119 
00120         if ((count == 0) &&
00121             (lti->inputCursorGlyph == lti->inputGlyphs) &&
00122             (lti->inputGlyphColIndex[lti->inputGlyphs] == lti->inputCols) &&
00123             (lti->inputColCharIndex[lti->inputCols] == lti->inputChars) &&
00124             (lti->inputLine[lti->inputChars] == U_TAB)) {
00125           /* Trailing TAB in prior input; delete it, and process it later */
00126           if (ltermDeleteGlyphs(lti, 1) != 0)
00127               return -1;
00128           processTrailingTab = 1;
00129         }
00130 
00131         /* Replace all input TABs with spaces */
00132         for (j=0; j < lti->inputChars; j++) {
00133           if (lti->inputLine[j] == U_TAB)
00134             lti->inputLine[j] = U_SPACE;
00135         }
00136       }
00137 
00138       LTERM_LOG(ltermPlainTextInput,21,
00139                 ("------------ Upgraded input mode=%d, trailingTab=%d\n\n",
00140                  lti->inputMode, processTrailingTab));
00141 
00142     }
00143 
00144     if (processTrailingTab) {
00145       /* Re-process trailing TAB */
00146       UNICHAR uch = U_TAB;
00147 
00148       assert(count == 0);
00149 
00150       LTERM_LOG(ltermPlainTextInput,21,("Reprocessing trailing TAB\n"));
00151 
00152       returnCode= ltermLineInput(lts, &uch, 1, opcodes);
00153       if (returnCode < 0)
00154         return returnCode;
00155 
00156     } else {
00157       /* Process new input characters */
00158       returnCode = ltermLineInput(lts, buf, count, opcodes) != 0;
00159       if (returnCode < 0)
00160         return returnCode;
00161     }
00162   }
00163 
00164   return 0;
00165 }
00166 
00167 
00172 int ltermCancelCompletion(struct lterms *lts)
00173 {
00174 
00175   LTERM_LOG(ltermCancelCompletion,40,
00176             ("++++++++++++ CANCELED COMPLETION REQUEST\n\n"));
00177 
00178   if (lts->completionRequest != LTERM_NO_COMPLETION) {
00179 
00180     /* Kill input line transmitted to process */
00181     if (ltermSendData(lts, lts->control+TTYKILL, 1) != 0)
00182       return -1;
00183 
00184     lts->completionRequest = LTERM_NO_COMPLETION;
00185   }
00186 
00187   return 0;
00188 }
00189 
00190 
00195 int ltermInsertChar(struct LtermInput *lti, UNICHAR uch)
00196 {
00197   UNICHAR* escapeSequence;
00198   int insChars, insertColIndex, insertCharIndex, j;
00199 
00200   LTERM_LOG(ltermInsertChar,40,("inserting character 0x%x at glyph %d\n",
00201                                    uch, lti->inputCursorGlyph));
00202 
00203   /* Ignore null character */
00204   if (uch == 0)
00205     return 0;
00206 
00207   escapeSequence = NULL;
00208   insChars = 1;
00209 
00210 #if 0
00211   /* COMMENTED OUT: Plain text not escaped; use code later in HTML insert */
00212   /* Check if plain text character needs to be escaped for XML/HTML */
00213   for (j=0; j<LTERM_PLAIN_ESCAPES; j++) {
00214 
00215     if (uch == ltermGlobal.escapeChars[j]) {
00216       /* Insert escape sequence rather than character */
00217       escapeSequence = ltermGlobal.escapeSeq[j];
00218       insChars =       ltermGlobal.escapeLen[j];
00219       LTERM_LOG(ltermInsertChar,42,("escape index=%d\n", j));
00220       break;
00221     }
00222   }
00223 #endif /* 0 */
00224 
00225   if (lti->inputChars+insChars > MAXCOLM1) {
00226     /* Input buffer overflow; ignore insert character */
00227     LTERM_WARNING("ltermInsertChar: Warning - input line buffer overflow\n");
00228     return 0;
00229   }
00230 
00231   assert(lti->inputChars >= 0);
00232   assert(lti->inputCols >= 0);
00233   assert(lti->inputGlyphs >= 0);
00234   assert(lti->inputCursorGlyph >= 0);
00235 
00236   assert(lti->inputCols <= lti->inputChars);
00237   assert(lti->inputGlyphs <= lti->inputCols);
00238 
00239   insertColIndex = lti->inputGlyphColIndex[lti->inputCursorGlyph];
00240   insertCharIndex = lti->inputColCharIndex[insertColIndex];
00241 
00242   LTERM_LOG(ltermInsertChar,41,("insertColIndex=%d, insertCharIndex=%d, insChars=%d\n",
00243            insertColIndex, insertCharIndex, insChars));
00244 
00245   /* Shift portion of input line to the right;
00246      remember that the column/glyph index arrays have an extra element */
00247   for (j=lti->inputChars - 1; j >= insertCharIndex; j--)
00248     lti->inputLine[j+insChars] = lti->inputLine[j];
00249 
00250   for (j=lti->inputCols; j >= insertColIndex; j--)
00251     lti->inputColCharIndex[j+1] = lti->inputColCharIndex[j]+insChars;
00252 
00253   for (j=lti->inputGlyphs; j >= lti->inputCursorGlyph; j--) {
00254     lti->inputGlyphCharIndex[j+1] = lti->inputGlyphCharIndex[j]+insChars;
00255     lti->inputGlyphColIndex[j+1] = lti->inputGlyphColIndex[j]+1;
00256   }
00257 
00258   /* Insert character(s) in input line */
00259   if (escapeSequence == NULL) {
00260     lti->inputLine[insertCharIndex] = uch;
00261   } else {
00262     for (j=0; j < insChars; j++)
00263       lti->inputLine[j+insertCharIndex] = escapeSequence[j];
00264   }
00265 
00266   /* Insert column/glyph */
00267   lti->inputColCharIndex[insertColIndex] = insertCharIndex;
00268 
00269   lti->inputGlyphCharIndex[lti->inputCursorGlyph] = insertCharIndex;
00270   lti->inputGlyphColIndex[lti->inputCursorGlyph] = insertColIndex;
00271 
00272   lti->inputChars += insChars;       /* Increment character count */
00273 
00274   lti->inputCols++;                  /* Increment column count */
00275 
00276   lti->inputGlyphs++;                /* Increment glyph count */
00277 
00278   lti->inputCursorGlyph++;           /* Reposition cursor */
00279 
00280   return 0;
00281 }
00282 
00283 
00285 void ltermSwitchToRawMode(struct lterms *lts)
00286 {
00287   struct LtermInput *lti = &(lts->ltermInput);
00288 
00289   LTERM_LOG(ltermSwitchToRawMode,40,("\n"));
00290 
00291   if (lti->inputMode != LTERM0_RAW_MODE) {
00292     /* Do other things ... */
00293     lti->inputMode = LTERM0_RAW_MODE;
00294   }
00295 }
00296 
00297 
00299 void ltermClearInputLine(struct lterms *lts)
00300 {
00301   struct LtermInput *lti = &(lts->ltermInput);
00302 
00303   LTERM_LOG(ltermClearInputLine,40,("\n"));
00304 
00305   lti->inputChars = 0;
00306 
00307   lti->inputCols = 0;
00308   lti->inputColCharIndex[0] = 0;
00309 
00310   lti->inputGlyphs = 0;
00311   lti->inputGlyphCharIndex[0] = 0;
00312   lti->inputGlyphColIndex[0] = 0;
00313 
00314   lti->inputCursorGlyph = 0;
00315 
00316   if (lts->maxInputMode >= LTERM2_EDIT_MODE)
00317     lti->inputMode = LTERM2_EDIT_MODE;
00318   else
00319     lti->inputMode = lts->maxInputMode;
00320 
00321   lti->escapeFlag = 0;
00322   lti->escapeCSIFlag = 0;
00323   lti->escapeCSIArg = 0;
00324 }
00325 
00326 
00337 static int ltermLineInput(struct lterms *lts,
00338                           const UNICHAR *buf, int count, int *opcodes)
00339 {
00340   struct LtermInput *lti = &(lts->ltermInput);
00341   UNICHAR uch;
00342   int charIndex, metaInput;
00343 
00344   /* Default returned opcodes (maybe overridden) */
00345   *opcodes = LTERM_LINEDATA_CODE | LTERM_INPUT_CODE;
00346 
00347   charIndex = 0;
00348 
00349   LTERM_LOG(ltermLineInput,30,
00350             ("count=%d, lti->inputMode=%d, inputCursorGlyph=%d\n",
00351              count, lti->inputMode, lti->inputCursorGlyph));
00352   LTERM_LOGUNICODE(ltermLineInput,31,(buf, count));
00353   LTERM_LOG(ltermLineInput,31,("Glyphs=%d,Cols=%d,Chars=%d\n",
00354                             lti->inputGlyphs, lti->inputCols, lti->inputChars));
00355 
00356   while (charIndex < count) {
00357     uch = buf[charIndex];
00358 
00359     if (uch == U_ESCAPE) {
00360       /* Escape */
00361       lti->escapeFlag = 1;
00362       uch = U_NUL;
00363 
00364     } else if (lti->escapeFlag) {
00365       /* Escaped character */
00366       lti->escapeFlag = 0;
00367 
00368       switch (uch) {
00369 
00370       case U_LBRACKET:
00371         /* Start of escape code sequence */
00372         lti->escapeCSIFlag = 1;
00373         lti->escapeCSIArg = 0;
00374         uch = U_NUL;
00375         break;
00376 
00377       default:
00378         uch = U_NUL;
00379       }
00380 
00381     } else if (lti->escapeCSIFlag) {
00382       /* Character part of escape code sequence */
00383 
00384       LTERM_LOG(ltermLineInput,38,("Escape code sequence - 0x%x\n", uch));
00385 
00386       if ((uch >= (UNICHAR)U_ZERO && uch <= (UNICHAR)U_NINE)) {
00387         /* Process numerical argument to escape code sequence */
00388         lti->escapeCSIArg = lti->escapeCSIArg*10 + (uch - U_ZERO);
00389         uch = U_NUL;
00390 
00391       } else {
00392         /* End of escape code sequence */
00393         lti->escapeCSIFlag = 0;
00394 
00395         /* NOTE: Input CSI escape sequence; may not be portable */
00396 
00397         /* SUN arrow key bindings */
00398         switch (uch) {
00399         case U_A_CHAR:
00400           uch = U_CTL_P;
00401           break;
00402         case U_B_CHAR:
00403           uch = U_CTL_N;
00404           break;
00405         case U_C_CHAR:
00406           uch = U_CTL_F;
00407           break;
00408         case U_D_CHAR:
00409           uch = U_CTL_B;
00410           break;
00411         default:
00412           uch = U_NUL;
00413         }
00414       }
00415     }
00416 
00417     if ( ((uch >= (UNICHAR)U_SPACE) && (uch != (UNICHAR)U_DEL)) ||
00418          ((uch == (UNICHAR)U_TAB) && (lti->inputMode <= LTERM2_EDIT_MODE)) ) {
00419       /* printable character or non-completion mode TAB; insert in buffer */
00420       /* (NEED TO UPDATE THIS CHECK FOR UNICODE PRINTABILITY) */
00421 
00422       LTERM_LOG(ltermLineInput,39,("inserting printable character - %c\n",
00423                    (char) uch));
00424 
00425       /* Insert character */
00426       if (ltermInsertChar(lti, uch) != 0)
00427         return -1;
00428 
00429     } else {
00430       /* Control character */
00431 
00432       /* Translate carriage returns to linefeeds in line mode
00433          (***NOTE*** may not be portable out of *nix) */
00434       if (uch == U_CRETURN)
00435         uch = U_LINEFEED;
00436 
00437       /* Line break control characters */
00438       if ( (uch == U_LINEFEED)               ||
00439            (uch == lts->control[TTYDISCARD]) ||
00440            (uch == lts->control[TTYSUSPEND]) ||
00441            (uch == lts->control[TTYINTERRUPT])) {
00442         /* Newline/TTYdiscard/TTYsuspend/TTYinterrupt character */
00443 
00444         /* Assert that linebreak character occurs at end of buffer;
00445          * enforced by lterm_write.
00446          */
00447         assert(charIndex == count-1);
00448 
00449         /* Check if meta input line */
00450         metaInput = ltermMetaInput(lts);
00451 
00452         if ((uch == lts->control[TTYDISCARD]) && !metaInput
00453             && (lts->commandNumber == 0)) {
00454           /* Not meta/command line; simply transmit discard character */
00455           if (ltermSendData(lts, lts->control+TTYDISCARD, 1) != 0)
00456             return -1;
00457 
00458         } else {
00459           /* Newline behaviour, with hide option */
00460           LTERM_LOG(ltermLineInput,31,("------------ NEWLINE (0x%x)\n\n",
00461                                          uch));
00462           LTERM_LOGUNICODE(ltermLineInput,31,( lti->inputLine,
00463                                                  lti->inputChars));
00464 
00465           /* The NEWLINE code tells ltermReturnInputLine to clear
00466            * the input line buffer after copying it
00467            */
00468           *opcodes = LTERM_LINEDATA_CODE | LTERM_INPUT_CODE
00469                                          | LTERM_NEWLINE_CODE;
00470 
00471           if (uch == lts->control[TTYDISCARD]) {
00472             *opcodes |= LTERM_HIDE_CODE;
00473             uch = U_LINEFEED;   /* essentially newline behaviour otherwise */
00474           }
00475 
00476           if (uch == lts->control[TTYINTERRUPT]) {
00477             /* Interrupt output operations, if necessary */
00478             if (ltermInterruptOutput(lts) != 0)
00479               return -1;
00480           }
00481 
00482           if (metaInput) {
00483             /* meta input; do not send line */
00484             *opcodes |= LTERM_META_CODE;
00485           } else {
00486             /* Send line and copy to echo buffer */
00487             if (ltermSendLine(lts, uch, (uch != U_LINEFEED),
00488                               LTERM_NO_COMPLETION) != 0)
00489               return -1;
00490           }
00491 
00492         }
00493 
00494       } else if (uch == lts->control[TTYKILL]) {
00495         /* kill line */
00496         ltermClearInputLine(lts);
00497 
00498         LTERM_LOG(ltermLineInput,31,("TTYKILL\n"));
00499 
00500       } else if ((uch == U_BACKSPACE) || (uch == U_DEL) ||
00501                  (uch == lts->control[TTYERASE])) {
00502         /* erase glyph */
00503         if (ltermDeleteGlyphs(lti, 1) != 0)
00504           return -1;
00505 
00506         LTERM_LOG(ltermLineInput,39,("TTYERASE=0x%x/0x%x\n",
00507                                      lts->control[TTYERASE], uch ));
00508 
00509       } else {
00510         /* other control characters */
00511 
00512         LTERM_LOG(ltermLineInput,32,("^%c\n", uch+U_ATSIGN));
00513 
00514         if (lti->inputMode < LTERM2_EDIT_MODE) {
00515           /* Non-edit mode; simply transmit control character */
00516           if (ltermSendData(lts, &uch, 1) != 0)
00517             return -1;
00518 
00519         } else {
00520           /* Edit input mode */
00521 
00522           if (uch == U_CTL_D) {
00523             /* Special handling for ^D */
00524 
00525             if (lti->inputChars == 0) {
00526               /* Lone ^D in input line, simply transmit it */
00527               if (ltermSendData(lts, &uch, 1) != 0)
00528                 return -1;
00529               uch = U_NUL;
00530 
00531             } else if (lti->inputCursorGlyph < lti->inputGlyphs) {
00532               /* Cursor not at end of line; delete to right */
00533               if (ltermDeleteGlyphs(lti, -1) != 0)
00534                 return -1;
00535               uch = U_NUL;
00536             }
00537           }
00538               
00539           switch (uch) {
00540 
00541           case U_NUL:                /* Null character; ignore */
00542             break;
00543 
00544           case U_CTL_B:              /* move cursor backward */
00545             if (lti->inputCursorGlyph > 0) {
00546               lti->inputCursorGlyph--;
00547             }
00548             break;
00549 
00550           case U_CTL_F:              /* move cursor forward */
00551             if (lti->inputCursorGlyph < lti->inputGlyphs) {
00552               lti->inputCursorGlyph++;
00553             }
00554             break;
00555 
00556           case U_CTL_A:              /* position cursor at beginning of line */
00557             lti->inputCursorGlyph = 0;
00558             break;
00559 
00560           case U_CTL_E:              /* position cursor at end of line */
00561             lti->inputCursorGlyph = lti->inputGlyphs;
00562             break;
00563 
00564           case U_CTL_K:              /* delete to end of line */
00565             if (ltermDeleteGlyphs(lti,-(lti->inputGlyphs-lti->inputCursorGlyph))
00566                 != 0)
00567               return -1;
00568             break;
00569 
00570           case U_CTL_L:              /* form feed */
00571           case U_CTL_R:              /* redisplay */
00572             break;
00573 
00574           case U_CTL_D:              /* ^D at end of non-null input line */
00575           case U_CTL_N:              /* dowN history */
00576           case U_CTL_P:              /* uP history */
00577           case U_CTL_Y:              /* yank */
00578           case U_TAB:                /* command completion */
00579 
00580             /* Assert that completion character occurs at end of buffer;
00581              * enforced by lterm_write.
00582              */
00583             assert(charIndex == count-1);
00584 
00585             metaInput = ltermMetaInput(lts);
00586 
00587             if (metaInput) {
00588               /* Meta input command completion */
00589               LTERM_LOG(ltermLineInput,40,
00590                         ("++++++++++++ meta COMPLETION uch=0x%X\n\n", uch));
00591               if (uch == U_TAB) {
00592                 *opcodes = LTERM_LINEDATA_CODE | LTERM_INPUT_CODE
00593                                                | LTERM_META_CODE
00594                                                | LTERM_COMPLETION_CODE;
00595               } else {
00596                 LTERM_WARNING("ltermLineInput: Warning - meta command completion not yet implemented for uch=0x%x\n", uch);
00597               }
00598 
00599             } else if (lti->inputMode >= LTERM3_COMPLETION_MODE) {
00600               /* Completion mode; non-completion TABs already processed */
00601 
00602               if (ltermRequestCompletion(lts, uch) != 0)
00603                 return -1;
00604             }
00605 
00606             break;
00607 
00608           default:              /* Transmit any other control character */
00609             if (ltermSendData(lts, &uch, 1) != 0)
00610               return -1;
00611           }
00612         }
00613       }
00614     }
00615 
00616     /* Increment character index */
00617     charIndex++;
00618   }
00619 
00620   return 0;
00621 }
00622 
00623 
00627 static int ltermMetaInput(struct lterms *lts)
00628 {
00629   struct LtermInput *lti = &(lts->ltermInput);
00630   UNICHAR *delimLoc, *ustr, *ustr2;
00631 
00632   LTERM_LOG(ltermMetaInput,40,("\n"));
00633 
00634   if (lts->options & LTERM_NOMETA_FLAG)
00635     return 0;
00636 
00637   /* Assert that there is at least one free character position in the buffer */
00638   assert(lti->inputChars < MAXCOL);
00639 
00640   /* Insert null character at the end of the input buffer */
00641   lti->inputLine[lti->inputChars] = U_NUL;
00642 
00643   /* Locate first occurrence of meta delimiter in input line */
00644   delimLoc = ucschr(lti->inputLine, ltermGlobal.metaDelimiter);
00645 
00646   if (delimLoc == NULL)
00647     return 0;
00648 
00649   for (ustr=lti->inputLine; ustr<delimLoc; ustr++)  /* skip spaces/TABs */
00650     if ((*ustr != U_SPACE) && (*ustr != U_TAB)) break;
00651 
00652   if (ustr == delimLoc) {
00653     /* Nameless meta command */
00654     LTERM_LOG(ltermMetaInput,41,("Nameless meta command\n"));
00655     return 1;
00656   }
00657 
00658   if (!IS_ASCII_LETTER(*ustr)) /* meta command must start with a letter */
00659     return 0;
00660 
00661   for (ustr2=ustr+1; ustr2<delimLoc; ustr2++)
00662     if (!IS_ASCII_LETTER(*ustr2) && !IS_ASCII_DIGIT(*ustr2))
00663       return 0;
00664 
00665   LTERM_LOG(ltermMetaInput,41,("Named meta command\n"));
00666 
00667   return 1;
00668 }
00669 
00670 
00676 static int ltermRequestCompletion(struct lterms *lts, UNICHAR uch)
00677 {
00678   LTERM_LOG(ltermRequestCompletion,40,
00679             ("++++++++++++ COMPLETION REQUEST uch=0x%X\n\n", uch));
00680 
00681   switch (uch) {
00682   case U_TAB:
00683     /* Send line and copy to echo buffer */
00684     if (ltermSendLine(lts, uch, 0, LTERM_TAB_COMPLETION) != 0)
00685       return -1;
00686     break;
00687   case U_CTL_P:
00688   case U_CTL_N:
00689     /* Send line and copy to echo buffer */
00690     if (ltermSendLine(lts, uch, 0, LTERM_HISTORY_COMPLETION) != 0)
00691       return -1;
00692     break;
00693   default:
00694     LTERM_WARNING("ltermCompletionRequest: Warning - command completion not yet implemented for uch=0x%x\n", uch);
00695   }
00696 
00697   return 0;
00698 }
00699 
00700 
00707 int ltermDeleteGlyphs(struct LtermInput *lti, int count)
00708 {
00709   int leftGlyph, leftColIndex, leftCharIndex;
00710   int rightGlyph, rightColIndex, rightCharIndex;
00711   int deleteGlyphs, deleteCols, deleteChars, j;
00712 
00713   LTERM_LOG(ltermDeleteGlyphs,40,("deleting %d glyphs from glyph %d\n",
00714             count, lti->inputCursorGlyph));
00715 
00716   if (count >= 0) {
00717     /* Delete to the left */
00718     deleteGlyphs = count;
00719 
00720     /* Limit the number of glyphs deleted to that present to the left */
00721     if (deleteGlyphs > lti->inputCursorGlyph)
00722       deleteGlyphs = lti->inputCursorGlyph;
00723 
00724     rightGlyph = lti->inputCursorGlyph;
00725     leftGlyph = rightGlyph - deleteGlyphs;
00726 
00727   } else {
00728     /* Delete to the right */
00729     deleteGlyphs = -count;
00730 
00731     /* Limit the number of glyphs deleted to that present to the right */
00732     if (deleteGlyphs > (lti->inputGlyphs - lti->inputCursorGlyph))
00733       deleteGlyphs = lti->inputGlyphs - lti->inputCursorGlyph;
00734 
00735     leftGlyph = lti->inputCursorGlyph;
00736     rightGlyph = leftGlyph + deleteGlyphs;
00737   }
00738 
00739   leftColIndex = lti->inputGlyphColIndex[leftGlyph];
00740   leftCharIndex = lti->inputGlyphCharIndex[leftGlyph];
00741 
00742   rightColIndex = lti->inputGlyphColIndex[rightGlyph];
00743   rightCharIndex = lti->inputGlyphCharIndex[rightGlyph];
00744 
00745   deleteCols =  rightColIndex  - leftColIndex;
00746   deleteChars = rightCharIndex - leftCharIndex;
00747 
00748   LTERM_LOG(ltermDeleteGlyphs,41,("deleteCols=%d, deleteChars=%d\n",
00749                                     deleteCols, deleteChars));
00750 
00751   LTERM_LOG(ltermDeleteGlyphs,42,("leftGlyph=%d, leftCol=%d, leftChar=%d\n",
00752                                     leftGlyph, leftColIndex, leftCharIndex));
00753 
00754   LTERM_LOG(ltermDeleteGlyphs,42,("rightGlyph=%d, rightCol=%d, rightChar=%d\n",
00755                                     rightGlyph, rightColIndex, rightCharIndex));
00756 
00757   /* Shift portion of input line to the left;
00758      remember that the column/glyph index arrays have an extra element */
00759   for (j = leftCharIndex; j < lti->inputChars-deleteChars; j++)
00760     lti->inputLine[j] = lti->inputLine[j+deleteChars];
00761 
00762   for (j = leftColIndex; j <= lti->inputCols-deleteCols; j++)
00763     lti->inputColCharIndex[j] =  lti->inputColCharIndex[j+deleteCols]
00764                                - deleteChars;
00765 
00766   for (j = leftGlyph; j <= lti->inputGlyphs-deleteGlyphs; j++)
00767     lti->inputGlyphColIndex[j] =  lti->inputGlyphColIndex[j+deleteGlyphs]
00768                                 - deleteCols;
00769 
00770   lti->inputChars -= deleteChars;             /* Decrement character count */
00771 
00772   lti->inputCols -= deleteCols;               /* Decrement column count */
00773 
00774   lti->inputGlyphs -= deleteGlyphs;           /* Decrement glyph count */
00775 
00776   if (count > 0)
00777     lti->inputCursorGlyph -= deleteGlyphs;    /* Reposition glyph cursor */
00778 
00779   return 0;
00780 }
00781 
00782 
00789 int ltermSendData(struct lterms *lts, const UNICHAR *buf, int count)
00790 {
00791   char ch, ptyBuf[MAXPTYIN];
00792   int remainingChars, chunkSize, success;
00793 
00794   assert(lts != NULL);
00795   assert(count >= 0);
00796 
00797   LTERM_LOG(ltermSendData,40,("count=%d\n", count));
00798   LTERM_LOGUNICODE(ltermSendData,41,(buf, count));
00799 
00800   if ((count == 1) && (*buf < 0x80)) { 
00801     /* Optimized code to transmit single ASCII character */
00802     ch = (char) *buf;
00803 
00804     if (lts->ptyMode)
00805 #ifndef USE_NSPR_IO
00806       success = (write(lts->pty.ptyFD, &ch, 1) == 1);
00807 #else
00808       assert(0);
00809 #endif
00810     else
00811       success = (WRITE(lts->ltermProcess.processIN, &ch, 1) == 1);
00812 
00813     if (!success) {
00814 #if defined(DEBUG_LTERM) && !defined(USE_NSPR_IO)
00815       int errcode = errno;
00816       perror("ltermSendData");
00817 #else
00818       int errcode = 0;
00819 #endif
00820       LTERM_ERROR("ltermSendData: Error %d in writing to child STDIN\n",
00821                   errcode);
00822       return -1;
00823     }
00824 
00825     return 0;
00826   }
00827 
00828   remainingChars = count;
00829   while (remainingChars > 0) {
00830     /* Convert Unicode to UTF8 */
00831     ucstoutf8(&buf[count-remainingChars], remainingChars,
00832               ptyBuf, MAXPTYIN,
00833               &remainingChars, &chunkSize);
00834 
00835     assert(chunkSize > 0);
00836 
00837     LTERM_LOG(ltermSendData,42,("remainingChars=%d, chunkSize=%d\n",
00838                                  remainingChars, chunkSize));
00839 
00840     /* Send UTF8 to process */
00841     if (ltermSendChar(lts, ptyBuf, chunkSize) != 0)
00842       return -1;
00843   }
00844 
00845   return 0;
00846 }
00847 
00848 
00852 int ltermSendChar(struct lterms *lts, const char *buf, int count)
00853 {
00854   int success;
00855 
00856   LTERM_LOG(ltermSendChar,50,("count=%d\n", count));
00857 
00858   if (lts->ptyMode)
00859 #ifndef USE_NSPR_IO
00860     success = (write(lts->pty.ptyFD, buf,
00861                      (SIZE_T) count) == count);
00862 #else
00863   assert(0);
00864 #endif
00865   else
00866     success = (WRITE(lts->ltermProcess.processIN, buf,
00867                      (SIZE_T) count) == count);
00868 
00869   if (!success) {
00870 #if defined(DEBUG_LTERM) && !defined(USE_NSPR_IO)
00871     int errcode = errno;
00872     perror("ltermSendChar");
00873 #else
00874     int errcode = 0;
00875 #endif
00876     LTERM_ERROR("ltermSendChar: Error %d in writing to child STDIN\n",
00877                 errcode);
00878     return -1;
00879   }
00880 
00881   return 0;
00882 }