コード例 #1
0
ファイル: HUtil.c プロジェクト: deardaniel/PizzaTest
/* PHName: parse hname and return list of matching models */
static void PHName(ILink *models,HMMSet *hset)
{
   if (trace & T_ITM)
      printf(" Models \n  ");

   SkipSpaces();
   if (ch == '(') {
      ReadCh();
      PHIdent(models,hset);
      SkipSpaces();
      while(ch == ',') {
         ReadCh();
         PHIdent(models,hset);
         SkipSpaces();
      }
      if (ch != ')')
         EdError(") expected");
      ReadCh();
   } else
      PHIdent(models,hset);
   if (trace & T_ITM) {
      printf("\n  %d models in itemlist\n",NumItems(*models));
      fflush(stdout);
   }
}
コード例 #2
0
ファイル: presentation.c プロジェクト: gap-packages/nq
/*
**    Generator() reads characters from the input stream until a non-
**    alphanumeric character is encountered. Only the first 127 characters
**    are significant as generator name and are copied into the global
**    array Gen[]. All other characters are discarded.
*/
static void     Generator(void) {

	int     i;

	for (i = 0; i < 127 && (isalnum(Ch) || Ch == '_' || Ch == '.'); i++) {
		Gen[i] = Ch;
		ReadCh();
	}
	Gen[i] = '\0';
	/* Discard the rest. */
	while (isalnum(Ch) || Ch == '_' || Ch == '.') ReadCh();
}
コード例 #3
0
ファイル: presentation.c プロジェクト: gap-packages/nq
/*
**    SkipBlanks() skips the characters ' ', '\t' and '\n' as well as
**    comments. A comment starts with '#' and finishes at the end of
**    the line.
*/
static void     SkipBlanks(void) {

	/* If Ch is empty, the next character is fetched. */
	if (Ch == '\0') ReadCh();

	/* First blank characters and comments are skipped. */
	while (Ch == ' ' || Ch == '\t' || Ch == '\n' || Ch == '#') {
		if (Ch == '#') {  /* Skip to the end of line. */
			while (Ch != '\n') ReadCh();
		}
		if (Ch == '\n') { Line++; Char = 0; }
		ReadCh();
	}
}
コード例 #4
0
ファイル: HUtil.c プロジェクト: deardaniel/PizzaTest
/* PItemSet: parse and item set appending items to ilist */
static void PItemSet(ILink *ilist, char *type, HMMSet *hset)
{
   ILink models = NULL;         /* list of hmms in item set */
   ILink p;

   PHName(&models,hset);        /* parse hname and get list of models */
   SkipSpaces();
   if (ch == '.') {             /* look for subcomponents */
      ReadCh();
      switch (GetKey()) {
      case TRANSP_KEY:
         AddTransP(models,ilist,type);
         break;
      case STATE_KEY:
         PState(models,ilist,type,hset);
         break;
      default:
         EdError("State or TransP expected");
      }
      FreeItems(&models);
   } else {                     /* append just the list of models to ilist */
      ChkType('h',type);
      p = *ilist;
      if (p==NULL)
         *ilist = models;
      else {
         while (p->next != NULL) p = p->next;
         p->next = models;
      }
   }
}
コード例 #5
0
ファイル: HUtil.c プロジェクト: deardaniel/PizzaTest
/* PState: parse state and add all matches in models to ilist */
static void PState(ILink models, ILink *ilist, char *type, HMMSet *hset)
{
   IntSet states;
   int j;
   HMMDef *hmm;
   ILink h;

   states = CreateSet(maxStates);
   PIndex(states);
   SkipSpaces();
   if (ch == '.') {
      ReadCh();
      PStatecomp(models,ilist,type,states,hset);
   } else {
      ChkType('s',type);
      for (h=models; h!=NULL; h=h->next) {
         hmm = h->owner;
         for (j=2; j<hmm->numStates; j++)
            if (IsMember(states,j)) {  /* tie ->info */
               if (trace & T_ITM)
                  printf(" %12s.state[%d]\n",
                         HMMPhysName(hset,hmm),j);
               AddItem(hmm,hmm->svec+j,ilist);
            }
      }
   }
   FreeSet(states);
}
コード例 #6
0
ファイル: HUtil.c プロジェクト: deardaniel/PizzaTest
/* PIndex: parse and index and return in s */
static void PIndex(IntSet s)
{
   SkipSpaces();
   if (ch != '[')
      EdError("[ expected");
   ReadCh();
   PIntRange(s);
   SkipSpaces();
   while (ch==',') {
      ReadCh();
      PIntRange(s);
      SkipSpaces();
   }
   if (ch != ']')
      EdError("] expected");
   ReadCh();
}
コード例 #7
0
ファイル: presentation.c プロジェクト: gap-packages/nq
/*
**    ReadCh() reads the next character from the current input file.
**    At the same time it checks for lines terminated with '\'. Such
**    a line is continued in the next line, therefore ReadCh() discards
**    '\' and the following '\n'.
*/
static void ReadCh(void) {

	Ch = getc(InFp);
	Char++;
	if (Ch == '\\') {
		Ch = getc(InFp);
		if (Ch == '\n') { Line++; Char = 0; ReadCh(); }
		else             { ungetc(Ch, InFp); Ch = '\\'; }
	}
}
コード例 #8
0
ファイル: HUtil.c プロジェクト: deardaniel/PizzaTest
/* EXPORT->PItemList: parse items in item list setting ilist and type */
char *PItemList(ILink *ilist, char *type, HMMSet *hset,
                Source *s, Boolean itrace)
{
   int rtrace;

   /* Initialise static variables */
   rtrace=trace;
   if (itrace)
      trace|=T_ITM;
   source = s;
   maxMixes = MaxMixInSet(hset);
   maxStates = MaxStatesInSet(hset);
   position=pattern;
   *position=0;

   /* Parse item set */
   ReadCh();
   SkipSpaces();
   if (ch != '{')
      EdError("{ expected");
   ReadCh();
   PItemSet(ilist,type,hset);
   SkipSpaces();
   while (ch == ',') {
      ReadCh();
      PItemSet(ilist,type,hset);
      SkipSpaces();
   }
   if (ch != '}')
      EdError("} expected");

   if (trace & T_ITM)
      fflush(stdout);
   trace=rtrace;

   return(pattern);
}
コード例 #9
0
ファイル: HUtil.c プロジェクト: deardaniel/PizzaTest
/* PIntRange: parse an integer range and add its members to s */
static void PIntRange(IntSet s)
{
   int i,i1,i2;

   i1 = GetInt(1,s.nMembers);
   SkipSpaces();
   if (ch == '-') {
      ReadCh();
      i2 = GetInt(1,s.nMembers);
   }
   else
      i2=i1;
   for (i=i1; i<=i2; i++)
      AddMember(s,i);
}
コード例 #10
0
ファイル: presentation.c プロジェクト: gap-packages/nq
/*
**    Number reads a number from the input.
*/
static void Number(void) {

	unsigned int    m, n = 0, overflow = 0;

	while (isdigit(Ch)) {
		m = n;
		n = 10 * n + (Ch - '0');
		if ((n - (Ch - '0')) / 10 != m) { overflow = 1; break; }
		ReadCh();
	}

	if (overflow) {
		fprintf(stderr, "Integer overflow reading %u%c", m, Ch);
		ReadCh();
		while (isdigit(Ch)) { fprintf(stderr, "%c", Ch); ReadCh(); }
		fprintf(stderr, " in\n");
		SyntaxError((char *)0);
	} else if (n >= (1U << (8 * sizeof(unsigned int) - 1))) {
		fprintf(stderr, "Integer overflow reading %u in\n", n);
		SyntaxError((char *)0);
	}

	N = n;
}
コード例 #11
0
ファイル: HUtil.c プロジェクト: deardaniel/PizzaTest
/* GetInt: read integer coerced given range */
static int GetInt(int lo, int hi)
{
   char buf[20];
   int i = 0, num;

   SkipSpaces();
   if (!isdigit(ch))
      EdError("Int expected");
   while (isdigit(ch)) {
      if (i==19)
         EdError("Integer too long!");
      buf[i++] = ch; ReadCh();
   }
   buf[i] = '\0';
   num = atoi(buf);
   if (num<lo) num=lo;
   if (num>hi) num=hi;
   return num;
}
コード例 #12
0
ファイル: HUtil.c プロジェクト: deardaniel/PizzaTest
/* GetKey: get a keyword */
static Keyword GetKey(void)
{
   char buf[20];
   int i = 0;
   Keyword k;

   SkipSpaces();
   if (!isalpha(ch))
      EdError("Keyword expected");
   while (isalpha(ch)) {
      buf[i++] = toupper(ch); ReadCh();
      if (i==20)
         EdError("Keyword too long!");
   }
   buf[i] = '\0';
   for (k=TRANSP_KEY; k<=COV_KEY; k=(Keyword) (k+1))
      if (strcmp(keymap[k],buf) == 0 )
         return k;
   EdError("Unknown Keyword");
   return COV_KEY;  /* never reached -- make compiler happy */
}
コード例 #13
0
ファイル: HUtil.c プロジェクト: deardaniel/PizzaTest
/*  characters for unquoted strings */
static char *GetAlpha(char *s)
{
   static char term[]=".,)}";
   Boolean wasQuoted;
   int i,n,q;

   wasQuoted=FALSE;
   SkipSpaces();
   if (ch == DBL_QUOTE || ch == SING_QUOTE){
      wasQuoted = TRUE; q = ch;
      ReadCh();
   }
   for (i=0; i<MAXSTRLEN ; i++){
      if (wasQuoted){
         if (ch == q) {
            ReadCh();
            s[i] = '\0';
            return s;
         }
      } else {
         if (isspace(ch) || strchr(term,ch)){
            s[i] = '\0';
            return s;
         }
      }
      if (ch==ESCAPE_CHAR) {
         ReadCh();
         if (ch<'0' || ch>'7') {
            n = ch - '0'; ReadCh();
            if (ch<'0' || ch>'7') EdError("Octal digit expected");
            n = n*8 + ch - '0'; ReadCh();
            if (ch<'0' || ch>'7') EdError("Octal digit expected");
            ch += n*8 - '0';
         }
      }
      s[i] = ch; ReadCh();
   }
   EdError("String too long");
   return NULL;         /* never reached -- make compiler happy */
}
コード例 #14
0
ファイル: HUtil.c プロジェクト: deardaniel/PizzaTest
/* PStatecomp: parse a statecomp */
static void PStatecomp(ILink models, ILink *ilist, char *type,
                       IntSet states, HMMSet *hset)
{
   HMMDef *hmm;
   ILink h;
   int s,j;
   IntSet streams;
   Keyword kw;

   switch(kw=GetKey()) {
   case MIX_KEY:
   case STREAM_KEY:
      if (hset->hsKind==TIEDHS || hset->hsKind==DISCRETEHS)
         HError(7231,"PStatecomp: Cannot specify streams or mixes unless continuous");
      streams = CreateSet(SMAX);
      if(kw==STREAM_KEY) {
         PIndex(streams);
         SkipSpaces();
         if (ch != '.')
            EdError(". expected after stream spec");
         ReadCh();
         if (GetKey() != MIX_KEY)
            EdError("Mix expected after Stream index");
      } else
         AddMember(streams,1);
      SkipSpaces();
      if (ch=='[')
         PMix(models,ilist,type,states,streams,hset);
      else {
         ChkType('p',type);
         for (h=models; h!=NULL; h=h->next) {
            hmm = h->owner;
            for (j=2; j<hmm->numStates; j++)
               if (IsMember(states,j))
                  for (s=1; s<=hset->swidth[0];s++)
                     if (IsMember(streams,s)) { /* tie -> spdf */
                        if (trace & T_ITM)
                           printf(" %12s.state[%d].stream[%d]\n",
                                  HMMPhysName(hset,hmm),j,s);
                        AddItem(hmm,hmm->svec[j].info->pdf+s,ilist);
                     }
         }
      }
      FreeSet(streams);
      break;
   case DUR_KEY:
      ChkType('d',type);
      for (h=models; h!=NULL; h=h->next) {
         hmm = h->owner;
         for (j=2; j<hmm->numStates; j++)
            if (IsMember(states,j)) {  /* tie ->dur */
               if (trace & T_ITM)
                  printf(" %12s.state[%d].dur\n",
                         HMMPhysName(hset,hmm),j);
               AddItem(hmm,hmm->svec[j].info,ilist);
            }
      }
      break;
   case WEIGHTS_KEY:
      ChkType('w',type);
      for (h=models; h!=NULL; h=h->next) {
         hmm = h->owner;
         for (j=2; j<hmm->numStates; j++)
            if (IsMember(states,j)) { /* tie ->stream weights */
               if (trace & T_ITM)
                  printf(" %12s.state[%d].weights\n",
                         HMMPhysName(hset,hmm),j);
               AddItem(hmm,hmm->svec[j].info,ilist);
            }
      }
      break;
   default:
      EdError("dur, weight, stream or mix expected");
   }
}
コード例 #15
0
ファイル: HUtil.c プロジェクト: deardaniel/PizzaTest
/* PMix: parse a mixture spec */
static void PMix(ILink models, ILink *ilist, char *type,
                 IntSet states, IntSet streams,HMMSet *hset)
{
   IntSet mixes;
   HMMDef *hmm;
   ILink h;
   int s,j,m;
   MixtureElem *me;
   StreamElem *ste;
   enum {TMIX, TMEAN, TCOV} what;

   mixes = CreateSet(maxMixes);
   PIndex(mixes);
   SkipSpaces();
   what = TMIX;
   if (ch == '.') {
      ReadCh();
      switch(GetKey()) {
      case MEAN_KEY:
         what = TMEAN; ChkType('u',type); break;
      case COV_KEY:
         what = TCOV;
         ChkType('a',type);
         break;
      default:
         EdError("Mean or Cov expected");
      }
   } else
      ChkType('m',type);
   for (h=models; h!=NULL; h=h->next) {
      hmm = h->owner;
      for (j=2; j<hmm->numStates; j++)
         if (IsMember(states,j)) {
            ste = hmm->svec[j].info->pdf+1;
            for (s=1; s<=hset->swidth[0]; s++,ste++)
               if (IsMember(streams,s)) {
                  me = ste->spdf.cpdf+1;
                  for (m=1; m<=ste->nMix; m++,me++)
                     if (me->weight>MINMIX && IsMember(mixes,m)) {
                        switch (what) {
                        case TMIX: /* tie ->mpdf */
                           if (trace & T_ITM)
                              printf(" %12s.state[%d].stream[%d].mix[%d]\n",
                                     HMMPhysName(hset,hmm),j,s,m);
                           AddItem(hmm,me,ilist);
                           break;
                        case TMEAN: /* tie ->mean */
                           ChkType('u',type);
                           if (trace & T_ITM)
                              printf(" %12s.state[%d].stream[%d].mix[%d].mean\n",
                                     HMMPhysName(hset,hmm),j,s,m);
                           AddItem(hmm,me->mpdf,ilist); break;
                        case TCOV: /* tie ->cov  */
                           switch (me->mpdf->ckind) {
                           case INVDIAGC:
                           case DIAGC:
                              ChkType('v',type); break;
                           case FULLC:
                              ChkType('i',type); break;
                           case LLTC:
                              ChkType('c',type); break;
                           case XFORMC:
                              ChkType('x',type); break;
                           }
                           if (trace & T_ITM)
                              printf(" %12s.state[%d].stream[%d].mix[%d].%c\n",
                                     HMMPhysName(hset,hmm),j,s,m,*type);
                           AddItem(hmm,me->mpdf,ilist);
                           break;
                        }
                     }
               }
         }
   }
   FreeSet(mixes);
}
コード例 #16
0
ファイル: nrctbl.c プロジェクト: OS2World/APP-INTERNET-Tin
/*
 * get_newsrcname()
 * get name of newsrc file with given name of nntp server
 * returns TRUE if name was found, FALSE if the search failed
 */
int
get_newsrcname(
	char *newsrc_name,
	const char *nntpserver_name) /* return value is always ignored */
{
	FILE *fp;
	char *line_entry;
	char line[LEN];
	char name_found[PATH_LEN];
	int line_entry_counter;
	int found = 0;
	t_bool do_cpy = FALSE;

	if ((fp = fopen(local_newsrctable_file, "r")) != NULL) {
		while ((fgets(line, (int) sizeof(line), fp) != NULL) && (found != 1)) {
			line_entry_counter = 0;

			if (!strchr("# ;", line[0])) {
				while ((line_entry = strtok(line_entry_counter ? NULL : line, " \t\n")) != NULL) {
					line_entry_counter++;

					if ((line_entry_counter == 1) && (!strcasecmp(line_entry, nntpserver_name))) {
						found = 1;
						do_cpy = TRUE;
					}

					if ((line_entry_counter == 1) && ((!strcasecmp(line_entry, "default")) || (!strcmp(line_entry, "*")))) {
						found = 2;
						do_cpy = TRUE;
					}
					if (do_cpy && (line_entry_counter == 2)) {
						strcpy(name_found, line_entry);
						do_cpy = FALSE;
					}
				}
			}
		}
		fclose(fp);
		if (found) {
			char dir[PATH_LEN];
			char tmp_newsrc[PATH_LEN];
			int error = 0;

			if (!strfpath(name_found, tmp_newsrc, sizeof(tmp_newsrc), NULL)) {
					my_fprintf(stderr, _("couldn't expand %s\n"), name_found);
					error = 1;
			} else {
				if (tmp_newsrc[0] == '/')
					(void) strcpy(newsrc_name, tmp_newsrc);
				else
					joinpath(newsrc_name, homedir, tmp_newsrc);
			}
			(void) strcpy(dir, newsrc_name);
			if (strchr(dir, '/'))
				*strrchr(dir, '/') = (char) 0;

			if (!error) {
			/* FIXME - write a global permssion check routine */
				if (access(dir, X_OK)) {
					my_fprintf(stderr, _(txt_error_no_enter_permission), dir);
					error = 1;
				} else if (access(newsrc_name, F_OK)) {
					my_fprintf(stderr, _(txt_error_no_such_file), newsrc_name);
					error = 2;
				} else if (access(dir, R_OK)) {
					my_fprintf(stderr, _(txt_error_no_read_permission), dir);
					error = 1;
				} else if (access(newsrc_name, R_OK)) {
					my_fprintf(stderr, _(txt_error_no_read_permission), newsrc_name);
					error = 1;
				} else if (access(dir, W_OK)) {
					my_fprintf(stderr, _(txt_error_no_write_permission), dir);
					error = 1;
				} else if (access(newsrc_name, W_OK)) {
					my_fprintf(stderr, _(txt_error_no_write_permission), newsrc_name);
					error = 1;
				}
			}
			if (error) {
				char ch;
				char default_ch = map_to_local(iKeyNrctblAlternative, &menukeymap.nrctbl_create);

				do {
					/* very ugly code, but curses is not initialized yet */
					if (error >= 2) {
						default_ch = map_to_local(iKeyNrctblCreate, &menukeymap.nrctbl_create);
						printf("%s%c\b", _(txt_nrctbl_create), default_ch);
					} else
						printf("%s%c\b", _(txt_nrctbl_default), default_ch);

					if ((ch = (char) ReadCh()) == '\r' || ch == '\n')
						ch = default_ch;
				} while (!strchr(menukeymap.nrctbl_create.localkeys, ch));
				printf("%c\n", ch);

				switch (map_to_default(ch, &menukeymap.nrctbl_create)) {
					case iKeyNrctblCreate:
						/* FIXME this doesn't check if we could create the file */
						return TRUE;

					case iKeyNrctblDefault:
						joinpath(newsrc_name, homedir, ".newsrc");
						return TRUE;

					case iKeyNrctblAlternative:
						sprintf(name_found, ".newsrc-%s", nntpserver_name);
						joinpath(newsrc_name, homedir, name_found);
						return TRUE;

					case iKeyNrctblQuit:
						exit(EXIT_SUCCESS);
						/* keep lint quiet: */
						/* FALLTHROUGH */

					case ESC:
					default:
						return TRUE;
				}
			}
			return TRUE;
		}
	} else
		write_newsrctable_file();

	return FALSE;
}
コード例 #17
0
ファイル: HUtil.c プロジェクト: deardaniel/PizzaTest
/* SkipSpaces: skip white space */
static void SkipSpaces(void)
{
   while (isspace(ch)) ReadCh();
}
コード例 #18
0
ファイル: curses.c プロジェクト: LambdaCalculus379/SLS-1.02
int InitScreen ()
{
#ifndef			INDEX_DAEMON

	char c,*ptr,buf[32];

	/* 
	 * we're going to assume a terminal here... 
	 */

	_clearscreen	= "\033[1;1H\033[J";
	_moveto		= "\033[%d;%dH";	/* not a termcap string! */
	_cleartoeoln	= "\033[K";
	_cleartoeos	= "\033[J";

	_setinverse	= "\033[7m";
	_clearinverse	= "\033[0m";
	_setunderline	= "\033[4m";
	_clearunderline	= "\033[0m";
	_terminalinit	= "\033c";
	_terminalend	= "\033c";
	_keypadlocal	= "";
	_keypadxmit	= "";

	InitWin ();

	_lines = _columns = -1;

	/* 
	 * Get lines and columns from environment settings - useful when
         * you're using something other than an Amiga window 
         */
         
	if (ptr = getenv("LINES")) {
		_lines = atol(ptr);
	}
	if (ptr = getenv("COLUMNS")) {
		_columns = atol(ptr);
	}

	/* 
	 * If that failed, try get a response from the console itself 
	 */

	if (_lines == -1 || _columns == -1) {
		Raw (TRUE);

		tputs ("\2330 q",1,outchar);	/* identify yourself */
		fflush (stdout);

getsize:
		while (ReadCh () != 0x9b) {
			;	/* Look for escape */
		}
		/* get top */
		ptr = buf;
		do {	
			c = *ptr++ = ReadCh ();
		} while (isdigit(c));

		if (c != ';') { 
			goto getsize;
		}
		
		/* get right */
		ptr = buf;
		do {	
			c = *ptr++ = ReadCh ();
		} while (isdigit(c));

		if (c != ';') { 
			goto getsize;
		}
		
		/* get bottom */
		ptr = buf;
		do {	
			c = *ptr++ = ReadCh ();
		} while (isdigit(c));

		if (c != ';') {
			goto getsize;
		}

		*ptr = 0;
		_lines = atol (buf);

		/* get right */
		ptr = buf;
		do {	
			c = *ptr++ = ReadCh ();
		} while (isdigit(c));

		if (c != ' ') {
			goto getsize;
		}
		if (ReadCh () != 'r') { 
			goto getsize;
		}

		*ptr = 0;
		_columns = atol (buf);
	}

	Raw (FALSE);

	return (TRUE);
#else
	return (FALSE);

#endif /* INDEX_DAEMON */
}
コード例 #19
0
ファイル: presentation.c プロジェクト: gap-packages/nq
/*
**    NextToken reads the next token from the input stream. It first
**    skips all the blank characters and comments.
*/
static void NextToken(void) {
	SkipBlanks();
	TChar = Char;
	TLine = Line;
	switch (Ch) {
	case '(':
	{ Token = LPAREN; ReadCh(); break; }
	case ')':
	{ Token = RPAREN; ReadCh(); break; }
	case '[':
	{ Token = LBRACK; ReadCh(); break; }
	case ']':
	{ Token = RBRACK; ReadCh(); break; }
	case '{':
	{ Token = LBRACE; ReadCh(); break; }
	case '}':
	{ Token = RBRACE; ReadCh(); break; }

	case '*':
	{ Token = MULT;   ReadCh(); break; }
	case '^':
	{ Token = POWER;  ReadCh(); break; }
	case ':': {
		ReadCh();
		if (Ch != '=') SyntaxError("illegal character");
		Token = DEQUALL;
		ReadCh();
		break;
	}
	case '=': {
		ReadCh();
		if (Ch != ':') Token = EQUAL;
		else { Token = DEQUALR; ReadCh(); }
		break;
	}

	case '+':
	{ Token = PLUS;   ReadCh(); break; }
	case '-':
	{ Token = MINUS;  ReadCh(); break; }

	case '<':
	{ Token = LANGLE; ReadCh(); break; }
	case '>':
	{ Token = RANGLE; ReadCh(); break; }

	case '|':
	{ Token = PIPE;      ReadCh(); break; }
	case ',':
	{ Token = COMMA;     ReadCh(); break; }
	case ';':
	{ Token = SEMICOLON; ReadCh(); break; }

	case '0':
	case '1' :
	case '2' :
	case '3' :
	case '4' :
	case '5':
	case '6' :
	case '7' :
	case '8' :
	case '9' :
	{ Token = NUMBER; Number(); break; }
	default :
		if (isalnum(Ch) || Ch == '_' || Ch == '.')
		{ Token = GEN; Generator(); break; }
		else SyntaxError("illegal character");
	}
	/*      printf( "# NextToken(): %s\n", TokenName[Token] );*/
}
コード例 #20
0
ファイル: alias.c プロジェクト: wfp5p/elm
void alias(void)
{
/*
 *	Work with alias commands...
 */

	char name[NLEN], *address, buffer[SLEN];
	char *commap;
	static int  newaliases = 0;
	int  ch, i;
	int nutitle = 0;
	int too_long;

/*
 *	We're going to try to match the way elm does it at
 * 	he main menu.  I probably won't be able to use any
 *	main menu routines, but I will "borrow" from them. RLH
 */

	alias_main_state();		/* Save globals for return to main menu */

	open_alias_files(FALSE);	/* First, read the alias files. RLH */

	alias_screen(newaliases);

	while (1) {

	  redraw = 0;
	  nucurr = 0;
	  nufoot = 0;

	  prompt(nls_Prompt);
	  CleartoEOLN();
	  ch = GetKey(0);

	  MoveCursor(LINES-3,strlen(nls_Prompt)); CleartoEOS();

	  dprint(3, (debugfile, "\n-- Alias command: %c\n\n", ch));

	  switch (ch) {
	    case '?': redraw += alias_help();			break;

#ifdef ALLOW_SUBSHELL
	    case '!' : WriteChar('!');
	      alias_main_state(); /** reload index screen vars **/
	      redraw += subshell();
	      alias_main_state(); /** reload alias screen vars **/
	      break;
#endif /* ALLOW_SUBSHELL */

	    case '$': PutLine(-1, -1, catgets(elm_msg_cat,
					AliasesSet, AliasesResync,
					"Resynchronize aliases..."));
	           /*
	            * Process deletions and then see if we need to
	            * re-run the "newalias" routine.
	            */
		      if (resync_aliases(newaliases)) {
		        install_aliases();
	                newaliases = 0;
		        redraw++;
		      }
		      break;

	    case 'a': PutLine(-1, -1, catgets(elm_msg_cat,
					AliasesSet, AliasesAddCurrent,
					"Add address from current message..."));
		      clear_error();
		      if (add_current_alias()) {
		          newaliases++;
		          nutitle++;
		      }
		      break;

	    case 'c':
	              if (curr_alias > 0) {
			  PutLine(-1, -1, catgets(elm_msg_cat,
	                              AliasesSet, AliasesReplaceCurrent,
	                              "Replace current alias in database..."));
		          clear_error();
		          if (add_alias(TRUE, curr_alias-1)) {
		              newaliases++;
		              nutitle++;
		          }
	              }
	              else {
		          show_error(catgets(elm_msg_cat,
	                          AliasesSet, AliasesNoneToReplace,
				  "Warning: no aliases to replace!"));
	              }
		      break;

	    case 'e': PutLine(LINES-3, strlen(nls_Prompt),
	                  catgets(elm_msg_cat, AliasesSet, AliasesEdit,
	                      "Edit %s..."), ALIAS_TEXT);
	           /*
	            * Process aliases.text for deletions, etc.  You
	            * have to do this *before* checking current because
	            * all aliases could be marked for deletion.
	            */
	              (void) resync_aliases(newaliases);
	              if (edit_aliases_text()) {
	                  newaliases = 0;
	              }
		      redraw++;
		      break;

	    case 'm':
	              if (curr_alias > 0) {
			  PutLine(-1, -1, catgets(elm_msg_cat,
					  AliasesSet, AliasesMail, "Mail..."));
	                  redraw += a_sendmsg();
	              }
	              else {
		          show_error(catgets(elm_msg_cat,
	                          AliasesSet, AliasesNoneToMail,
				  "Warning: no aliases to send mail to!"));
	              }
		      break;

	    case 'n': PutLine(-1, -1, catgets(elm_msg_cat,
					AliasesSet, AliasesAddNew,
					"Add a new alias to database..."));
		      clear_error();
		      if (add_alias(FALSE, -1)) {
		          newaliases++;
		          nutitle++;
		      }
		      break;

	    case 'q':
	    case 'Q':
	    case 'i':
	    case 'I':
	    case 'r':
	    case 'R': PutLine(-1, -1, catgets(elm_msg_cat,
	    				AliasesSet, AliasesAddReturn,
					"Return to main menu..."));
	           /*
	            * leaving the alias system.  Must check for
	            * pending deletes, etc.  prompt is set to FALSE
	            * on uppercase letters so that deletions are
	            * NOT queried.
	            */
	              if (delete_aliases(newaliases, islower(ch))) {
	                install_aliases();
	                newaliases = 0;
	              }
		      clear_error();
		      alias_main_state();		/* Done with aliases. */
		      return;

	    case RETURN:
	    case LINE_FEED:
	    case ' ':
	    case 'v':
		      if (newaliases) {		/* Need this ?? */
		          show_error(catgets(elm_msg_cat,
	                          AliasesSet, AliasesNotInstalled,
				  "Warning: new aliases not installed yet!"));
	              }

	              if (curr_alias > 0) {
	                  if (aliases[curr_alias-1]->type & GROUP) {
	                      PutLine(LINES-1, 0, catgets(elm_msg_cat,
	                              AliasesSet, AliasesGroupAlias,
				      "Group alias: %-60.60s"),
	                          aliases[curr_alias-1]->address);
		          }
		          else {
	                      PutLine(LINES-1, 0, catgets(elm_msg_cat,
	                              AliasesSet, AliasesAliasedAddress,
				      "Aliased address: %-60.60s"),
	                          aliases[curr_alias-1]->address);
		          }
		      }
	              else {
		          show_error(catgets(elm_msg_cat,
	                          AliasesSet, AliasesNoneToView,
				  "Warning: no aliases to view!"));
		      }
		      break;

	    case 'x':
	    case 'X': PutLine(-1, -1, catgets(elm_msg_cat,
	    				AliasesSet, AliasesAddReturn,
					"Return to main menu..."));
	              exit_alias();
		      clear_error();
		      alias_main_state();		/* Done with aliases. */
		      return;

	    case 'f':
	    case 'F':
	              if (curr_alias > 0) {
		          clear_error();
		          strcpy(name, aliases[curr_alias-1]->alias);
		          if (ch == 'F') {
		              strcpy(buffer, catgets(elm_msg_cat,
	                              AliasesSet, AliasesFullyExpanded,
				      "Fully expand alias: "));
		              PutLine(LINES-2, 0, buffer);
			      if (enter_string(name, sizeof(name), -1, -1,
					  ESTR_REPLACE) < 0 || name[0] == '\0')
				break;
		          }
	                  too_long = FALSE;
		          address = get_alias_address(name, TRUE, &too_long);
		          if (address != NULL) {
		              while (TRUE) {
	                          ClearScreen();
			          PutLine(2,0, catgets(elm_msg_cat,
	                                  AliasesSet, AliasesAliasedFull,
					  "Aliased address for:\t%s\n\r"),
	                              name);
		                  i = 4;
		                  while (i < LINES-2) {
		                      if ((commap = strchr(address, (int)','))
	                                          == NULL) {
		                          PutLine(i, 4, address);
		                          break;
		                      }
		                      *commap = '\0';
		                      PutLine(i++, 4, address);
		                      address = commap+2;
		                  }
	                          PutLine(LINES-1, 0, catgets(elm_msg_cat,
	                                  AliasesSet, AliasesPressReturn,
					  "Press <return> to continue."));
			          (void) ReadCh();
		                  if (commap == NULL) {
			              redraw++;
		                      break;
		                  }
		              }
		          }
	                  else if (! too_long) {
			      show_error(catgets(elm_msg_cat,
	                              AliasesSet, AliasesNotFound,
				      "Not found."));
		          }
		      }
	              else {
		          show_error(catgets(elm_msg_cat,
	                          AliasesSet, AliasesNoneToView,
				  "Warning: no aliases to view!"));
		      }
		      break;

	  case KEY_REDRAW:
		      redraw = 1;
		      break;

	 /*
	  * None of the menu specific commands were chosen, therefore
	  * it must be a "motion" command (or an error).
	  */
	    default	: motion(ch);

	  }

	  if (redraw) {			/* Redraw screen if necessary */
	      alias_screen(newaliases);
	      nutitle = 0;
	  }

	  if (nutitle) {		/* Redraw title if necessary */
	      alias_title(newaliases);
	      nutitle = 0;
	  }

	  check_range();

	  if (nucurr == NEW_PAGE)
	    show_headers();
	  else if (nucurr == SAME_PAGE)
	    show_current();
	  else if (nufoot) {
	    if (mini_menu) {
	      MoveCursor(LINES-7, 0);
              CleartoEOS();
	      show_alias_menu();
	    }
	    else {
	      MoveCursor(LINES-4, 0);
	      CleartoEOS();
	    }
	    show_last_error();	/* for those operations that have to
				 * clear the footer except for a message.
				 */
	  }
	}			/* BIG while loop... */
}
コード例 #21
0
ファイル: alias.c プロジェクト: wfp5p/elm
static int alias_help(void)
{
/*
 *	Help section for the alias menu...
 *
 *	Return non-0 if main part of screen overwritten, else 0
 */

	int  ch;
	int  redraw=0;
	char *alias_prompt;


	if (mini_menu)
		alias_prompt = catgets(elm_msg_cat, AliasesSet, AliasesShortKey,
			"Key: ");
	else
		alias_prompt = catgets(elm_msg_cat, AliasesSet, AliasesLongKey,
			"Key you want help for: ");

	MoveCursor(LINES-3, 0);
	CleartoEOS();
	if (mini_menu) {
	  CenterLine(LINES-3, catgets(elm_msg_cat, AliasesSet, AliasesKeyMenu,
 "Press the key you want help for, '?' for a key list, or '.' to exit help"));
	}

	lower_prompt(alias_prompt);

	while ((ch = ReadCh()) != '.') {
	  switch(ch) {
	    case '?' : display_helpfile("alias");
		       redraw++;
		       return(redraw);

	    case '$': show_error(catgets(elm_msg_cat, AliasesSet, AliasesHelpDollar,
"$ = Force resynchronization of aliases, processing additions and deletions."));
		      break;

	    case '/': show_error(catgets(elm_msg_cat, AliasesSet, AliasesHelpSlash,
			"/ = Search for specified name or alias in list."));
		      break;

	    case RETURN:
	    case LINE_FEED:
	    case ' ':
	    case 'v': show_error(catgets(elm_msg_cat, AliasesSet, AliasesHelpv,
	    "v = View the address for the currently selected alias."));
		      break;

	    case 'a': show_error(catgets(elm_msg_cat, AliasesSet, AliasesHelpa,
	    "a = Add (return) address of current message to alias database."));
		      break;

	    case 'c': show_error(catgets(elm_msg_cat, AliasesSet, AliasesHelpc,
"c = Change current user alias, modifying alias database at next resync."));
		      break;

	    case 'd': show_error(catgets(elm_msg_cat, AliasesSet, AliasesHelpd,
	    "d = Mark the current alias for deletion from alias database."));
		      break;

	    case ctrl('D'): show_error(catgets(elm_msg_cat, AliasesSet, AliasesHelpCtrlD,
	    "^D = Mark for deletion user aliases matching specified pattern."));
		      break;

	    case 'e': show_error(catgets(elm_msg_cat, AliasesSet, AliasesHelpe,
	    "e = Edit the alias text file directly (will run newalias)."));
		      break;

	    case 'f': show_error(catgets(elm_msg_cat, AliasesSet, AliasesHelpf,
		"f = Display fully expanded address of current alias."));
		      break;

	    case 'l': show_error(catgets(elm_msg_cat, AliasesSet, AliasesHelpl,
	    "l = Limit displayed aliases on the specified criteria."));
		      break;

	    case ctrl('L'): show_error(catgets(elm_msg_cat, AliasesSet, AliasesHelpCtrlL,
		      "^L = Rewrite the screen."));
	    	      break;

	    case 'm': show_error(catgets(elm_msg_cat, AliasesSet, AliasesHelpm,
	    "m = Send mail to the current or tagged aliases."));
		      break;

	    case 'n': show_error(catgets(elm_msg_cat, AliasesSet, AliasesHelpn,
"n = Add a new user alias, adding to alias database at next resync."));
		      break;

	    case 'r':
	    case 'q':
	    case 'i': show_error(catgets(elm_msg_cat, AliasesSet, AliasesHelpi,
		      "r,q,i = Return from alias menu (with prompting)."));
	   	      break;

	    case 'R':
	    case 'Q':
	    case 'I': show_error(catgets(elm_msg_cat, AliasesSet, AliasesHelpQ,
		      "R,Q,I = Return from alias menu (no prompting)."));
	   	      break;

	    case 't': show_error(catgets(elm_msg_cat, AliasesSet, AliasesHelpt,
		      "t = Tag current alias for further operations."));
		      break;

	    case 'T': show_error(catgets(elm_msg_cat, AliasesSet, AliasesHelpT,
		      "T = Tag current alias and go to next alias."));
		      break;

	    case ctrl('T'): show_error(catgets(elm_msg_cat, AliasesSet, AliasesHelpCtrlT,
	    "^T = Tag aliases matching specified pattern."));
		      break;

	    case 'u': show_error(catgets(elm_msg_cat, AliasesSet, AliasesHelpu,
	    "u = Unmark the current alias for deletion from alias database."));
		      break;

	    case ctrl('U'): show_error(catgets(elm_msg_cat, AliasesSet, AliasesHelpCtrlU,
"^U = Mark for undeletion user aliases matching specified pattern."));
		      break;

	    case 'x':
	    case 'X': show_error(catgets(elm_msg_cat, AliasesSet, AliasesHelpX,
	    "x = Exit from alias menu, abandoning any pending deletions."));
	   	      break;

	    default : show_error(catgets(elm_msg_cat, AliasesSet, AliasesHelpNoHelp,
			"That key isn't used in this section."));
	   	      break;
	  }
	  lower_prompt(alias_prompt);
	}

	/* Remove help lines */
	MoveCursor(LINES-3, 0);	CleartoEOS();
	return(redraw);
}
コード例 #22
0
options()
{
	/** change options... **/
	/* return:
	 *	> 0	if restort was done - to indicate we might need to
	 *	 	change the page of our headers as a consequence
	 *		of the new sort order
	 *	< 0	if user entered 'x' to quit elm immediately
	 *	0	otherwise
	 */

	int	ch,
	     	resort = 0;
	char	*strcpy(),
	     	temp[SLEN];	/* needed when an option is run through
				 * expand_env(), because that function
				 * is destructive of the original
				 */

	display_options();

	clearerr(stdin);

	while(1) {
	  ClearLine(LINES-4);

	  Centerline(LINES-4,
 "Select first letter of option line, '>' to save, or 'i' to return to index.");

	  PutLine0(LINES-2, 0, "Command: ");

	  ch = ReadCh();
	  ch = tolower(ch);

	  clear_error();	/* remove possible "sorting" message etc... */

	  one_liner(one_liner_for(ch));

	  switch (ch) {
	    case 'c' : optionally_enter(raw_calendar_file, 2, 23, FALSE, FALSE);
		       strcpy(temp, raw_calendar_file);
		       expand_env(calendar_file, temp);
		       break;
	    case 'd' : optionally_enter(raw_pager, 3, 23, FALSE, FALSE);
		       strcpy(temp, raw_pager);
		       expand_env(pager, temp);
		       clear_pages = (equal(pager, "builtin+") ||
			             equal(pager, "internal+"));
		       break;
	    case 'e' : optionally_enter(raw_editor, 4, 23, FALSE, FALSE);
		       strcpy(temp, raw_editor);
		       expand_env(editor, temp);
	               break;
	    case 'f' : optionally_enter(raw_folders, 5, 23, FALSE, FALSE);
		       strcpy(temp, raw_folders);
		       expand_env(folders, temp);
		       break;
	    case 's' : if(change_sort(6,23)) resort++;			break;
	    case 'o' : optionally_enter(raw_sentmail, 7, 23, FALSE, FALSE);
		       strcpy(temp, raw_sentmail);
		       expand_env(sent_mail, temp);
		       break;
	    case 'p' : optionally_enter(raw_printout, 8, 23, FALSE, FALSE);
		       strcpy(temp, raw_printout);
		       expand_env(printout, temp);
		       break;
	    case 'y' : optionally_enter(full_username, 9, 23, FALSE, FALSE);
		       break;
	    case 'a' : on_or_off(&arrow_cursor, 12, 23); 		break;
	    case 'm' : on_or_off(&mini_menu, 13, 23);
		       headers_per_page = LINES - (mini_menu ? 13 : 8); break;

	    case 'u' : switch_user_level(&user_level,15, 23);		break;
	    case 'n' : on_or_off(&names_only, 16, 23);			break;

	    case '?' : options_help();
	               PutLine0(LINES-2,0,"Command: ");			break;

	    case '>' : printf("Save options in .elm/elmrc...");
		       fflush(stdout);    save_options();		break;

	    case 'x' :	return(-1);	/* exit elm */
	    case 'q' :	/* pop back up to previous level, in this case == 'i' */
	    case 'i' :  /* return to index screen */
			return(resort ? 1 : 0);
	    case ctrl('L'): display_options();				break;
	    default: error("Command unknown!");
	  }

	}
}
コード例 #23
0
ファイル: getline.c プロジェクト: OS2World/APP-INTERNET-Tin
char *
tin_getline(
	const char *prompt,
	int number_only,	/* 1=positive numbers only, 2=negative too */
	const char *str,
	int max_chars,
	t_bool passwd,
	int which_hist)
{
	int c, i, loc, tmp, gl_max;
#if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
	wint_t wc;
#else
	char *buf = gl_buf;
#endif /* MULTIBYTE_ABLE && !NO_LOCALE */

	is_passwd = passwd;

	set_xclick_off();
	if (prompt == NULL)
		prompt = "";

	gl_buf[0] = 0;		/* used as end of input indicator */
	gl_fixup(-1, 0);	/* this resets gl_fixup */
	gl_width = cCOLS - strlen(prompt);
	gl_prompt = prompt;
	gl_pos = gl_cnt = 0;

	if (max_chars == 0) {
		if (number_only)
			gl_max = 6;
		else
			gl_max = BUF_SIZE;
	} else
		gl_max = max_chars;

	my_fputs(prompt, stdout);
	cursoron();
	my_flush();

	if (gl_in_hook) {
		loc = gl_in_hook(gl_buf);
		if (loc >= 0)
			gl_fixup(0, BUF_SIZE);
	}

	if (!cmd_line && gl_max == BUF_SIZE)
		CleartoEOLN();

#if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
	if (str != NULL) {
		wchar_t wbuf[LEN];

		if (mbstowcs(wbuf, str, ARRAY_SIZE(wbuf) - 1) != (size_t) -1) {
			wbuf[ARRAY_SIZE(wbuf) - 1] = (wchar_t) '\0';
			for (i = 0; wbuf[i]; i++)
				gl_addwchar(wbuf[i]);
		}
	}

	while ((wc = ReadWch()) != WEOF) {
		if ((gl_cnt < gl_max) && iswprint(wc)) {
			if (number_only) {
				if (iswdigit(wc)) {
					gl_addwchar(wc);
				/* Minus */
				} else if (number_only == 2 && gl_pos == 0 && wc == (wint_t) '-') {
					gl_addwchar(wc);
				} else {
					ring_bell();
				}
			} else
				gl_addwchar(wc);
		} else {
			c = (int) wc;
			switch (wc) {
#else
	if (str != NULL) {
		for (i = 0; str[i]; i++)
			gl_addchar(str[i]);
	}

	while ((c = ReadCh()) != EOF) {
		c &= 0xff;
		if ((gl_cnt < gl_max) && my_isprint(c)) {
			if (number_only) {
				if (isdigit(c)) {
					gl_addchar(c);
				/* Minus */
				} else if (number_only == 2 && gl_pos == 0 && c == '-') {
					gl_addchar(c);
				} else {
					ring_bell();
				}
			} else
				gl_addchar(c);
		} else {
			switch (c) {
#endif /* MULTIBYTE_ABLE && !NO_LOCALE */
				case ESC:	/* abort */
#ifdef HAVE_KEY_PREFIX
				case KEY_PREFIX:
#endif /* HAVE_KEY_PREFIX */
					switch (get_arrow_key(c)) {
						case KEYMAP_UP:
						case KEYMAP_PAGE_UP:
							hist_prev(which_hist);
							break;

						case KEYMAP_PAGE_DOWN:
						case KEYMAP_DOWN:
							hist_next(which_hist);
							break;

						case KEYMAP_RIGHT:
							gl_fixup(-1, gl_pos + 1);
							break;

						case KEYMAP_LEFT:
							gl_fixup(-1, gl_pos - 1);
							break;

						case KEYMAP_HOME:
							gl_fixup(-1, 0);
							break;

						case KEYMAP_END:
							gl_fixup(-1, gl_cnt);
							break;

						case KEYMAP_DEL:
							gl_del(0);
							break;

						case KEYMAP_INS:
#if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
							gl_addwchar((wint_t) ' ');
#else
							gl_addchar(' ');
#endif /* MULTIBYTE_ABLE && !NO_LOCALE */
							break;

						default:
							return (char *) 0;
					}
					break;

				case '\n':	/* newline */
				case '\r':
					gl_newline(which_hist);
#if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
					wcstombs(buf, gl_buf, BUF_SIZE - 1);
#endif /* MULTIBYTE_ABLE && !NO_LOCALE */
					return buf;

				case CTRL_A:
					gl_fixup(-1, 0);
					break;

				case CTRL_B:
					gl_fixup(-1, gl_pos - 1);
					break;

				case CTRL_D:
					if (gl_cnt == 0) {
						gl_buf[0] = 0;
						my_fputc('\n', stdout);
#if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
						wcstombs(buf, gl_buf, BUF_SIZE - 1);
#endif /* MULTIBYTE_ABLE && !NO_LOCALE */
						return buf;
					} else
						gl_del(0);
					break;

				case CTRL_E:
					gl_fixup(-1, gl_cnt);
					break;

				case CTRL_F:
					gl_fixup(-1, gl_pos + 1);
					break;

				case CTRL_H:
				case DEL:
					gl_del(-1);
					break;

				case TAB:
					if (gl_tab_hook) {
						tmp = gl_pos;
						loc = gl_tab_hook(gl_buf, strlen(gl_prompt), &tmp);
						if (loc >= 0 || tmp != gl_pos)
							gl_fixup(loc, tmp);
					}
					break;

				case CTRL_W:
					gl_kill_back_word();
					break;

				case CTRL_U:
					gl_fixup(-1, 0);
					/* FALLTHROUGH */
				case CTRL_K:
					gl_kill();
					break;

				case CTRL_L:
				case CTRL_R:
					gl_redraw();
					break;

				case CTRL_N:
					hist_next(which_hist);
					break;

				case CTRL_P:
					hist_prev(which_hist);
					break;

				default:
					ring_bell();
					break;
			}
		}
	}
#if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
	wcstombs(buf, gl_buf, BUF_SIZE - 1);
#endif /* MULTIBYTE_ABLE && !NO_LOCALE */
	return buf;
}


/*
 * adds the character c to the input buffer at current location if
 * the character is in the allowed template of characters
 */
static void
#if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
gl_addwchar(
	wint_t wc)
#else
gl_addchar(
	int c)
#endif /* MULTIBYTE_ABLE && !NO_LOCALE */
{
	int i;

	/*
	 * Crashing is always the worst solution IMHO. So as a quick hack,
	 * ignore characters silently, if buffer is full. To allow a final
	 * newline, leave space for one more character. Just a hack too.
	 * This was the original code:
	 *
	if (gl_cnt >= BUF_SIZE - 1) {
		error_message("tin_getline: input buffer overflow");
		giveup();
	}
	 */
	if (gl_cnt >= BUF_SIZE - 2)
		return;

	for (i = gl_cnt; i >= gl_pos; i--)
		gl_buf[i + 1] = gl_buf[i];

#if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
	gl_buf[gl_pos] = (wchar_t) wc;
#else
	gl_buf[gl_pos] = c;
#endif /* MULTIBYTE_ABLE && !NO_LOCALE */
	gl_fixup(gl_pos, gl_pos + 1);
}


/*
 * Cleans up entire line before returning to caller. A \n is appended.
 * If line longer than screen, we redraw starting at beginning
 */
static void
gl_newline(
	int w)
{
	int change = gl_cnt;
	int len = gl_cnt;
	int loc = gl_width - 5;	/* shifts line back to start position */

	if (gl_cnt >= BUF_SIZE - 1) {
		/*
		 * Like above: avoid crashing if possible. gl_addchar() now
		 * leaves one space left for the newline, so this part of the
		 * code should never be reached. A proper implementation is
		 * desirable though.
		 */
		error_message("tin_getline: input buffer overflow");
		giveup();
	}
	hist_add(w);		/* only adds if nonblank */
	if (gl_out_hook) {
		change = gl_out_hook(gl_buf);
#if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
		len = wcslen(gl_buf);
#else
		len = strlen(gl_buf);
#endif /* MULTIBYTE_ABLE && !NO_LOCALE */
	}
	if (loc > len)
		loc = len;
	gl_fixup(change, loc);	/* must do this before appending \n */
#if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
	gl_buf[len] = (wchar_t) '\0';
#else
	gl_buf[len] = '\0';
#endif /* MULTIBYTE_ABLE && !NO_LOCALE */
}


/*
 * Delete a character. The loc variable can be:
 *    -1 : delete character to left of cursor
 *     0 : delete character under cursor
 */
static void
gl_del(
	int loc)
{
	int i;

	if ((loc == -1 && gl_pos > 0) || (loc == 0 && gl_pos < gl_cnt)) {
		for (i = gl_pos + loc; i < gl_cnt; i++)
			gl_buf[i] = gl_buf[i + 1];
		gl_fixup(gl_pos + loc, gl_pos + loc);
	} else
		ring_bell();
}