mirror of
git://git.code.sf.net/p/cdesktopenv/code
synced 2025-03-09 15:50:02 +00:00
665 lines
16 KiB
C
665 lines
16 KiB
C
/*
|
|
* CDE - Common Desktop Environment
|
|
*
|
|
* Copyright (c) 1993-2012, The Open Group. All rights reserved.
|
|
*
|
|
* These libraries and programs are free software; you can
|
|
* redistribute them and/or modify them under the terms of the GNU
|
|
* Lesser General Public License as published by the Free Software
|
|
* Foundation; either version 2 of the License, or (at your option)
|
|
* any later version.
|
|
*
|
|
* These libraries and programs are distributed in the hope that
|
|
* they will be useful, but WITHOUT ANY WARRANTY; without even the
|
|
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
|
* PURPOSE. See the GNU Lesser General Public License for more
|
|
* details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with these libraries and programs; if not, write
|
|
* to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
|
|
* Floor, Boston, MA 02110-1301 USA
|
|
*/
|
|
/* $XConsortium: conutil.c /main/3 1995/11/08 10:29:28 rswiston $ */
|
|
/*
|
|
Copyright 1986 Tandem Computers Incorporated.
|
|
This product and information is proprietary of Tandem Computers Incorporated.
|
|
Copyright (c) 1986, 1987, 1988, 1989 Hewlett-Packard Co.
|
|
*/
|
|
|
|
/* Conutil has utility procedures for program CONTEXT. */
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include "basic.h"
|
|
#include "trie.h"
|
|
|
|
#include "cont.h"
|
|
|
|
/* Output declaration of dlmptr */
|
|
void dumpdlmptr(void)
|
|
{
|
|
int n;
|
|
|
|
fprintf(delim, "M_DELIMEXTERN M_WCHAR *m_dlmptr[%d];\n", dcount+1);
|
|
fprintf(delim, "M_DELIMEXTERN char *mb_dlmptr[%d]\n", dcount+1);
|
|
fprintf(delim, "#if defined(M_DELIMDEF)\n = {\n");
|
|
for (n = 0 ; n < dcount ; n++) {
|
|
if (n) fputs(",\n", delim);
|
|
fprintf(delim, " %s", dlmptr[n]);
|
|
}
|
|
fprintf(delim, "%s", endif);
|
|
}
|
|
|
|
/* Output the generated data structures */
|
|
void dumptree(LOGICAL sparse)
|
|
{
|
|
int i, count = 0;
|
|
|
|
for (i = 0 ; i < ccount ; i++)
|
|
if (contree[i])
|
|
countdown(contree[i], &count);
|
|
fprintf(delim,
|
|
"M_DELIMEXTERN M_PTRIE m_delimtrie[%d]\n#if defined(M_DELIMDEF)\n = {\n",
|
|
count);
|
|
fprintf(context,
|
|
"M_CONEXTERN int m_contree[%d]\n#if defined(M_CONDEF)\n = {\n ",
|
|
ccount);
|
|
|
|
count = 0;
|
|
for (i = 0 ; i < ccount ; i++) {
|
|
if (contree[i]) {
|
|
fprintf(context, "%d", count + 1);
|
|
dumpnode(&first, delim, contree[i], &count, (void *)printval);
|
|
}
|
|
else fprintf(context, "0");
|
|
if (i < ccount - 1) fprintf(context, ",\n ");
|
|
}
|
|
fprintf(delim, "%s", endif);
|
|
fprintf(context, "%s", endif);
|
|
nextcon(sparse);
|
|
}
|
|
|
|
/* Enter a delimiter into the delimiter tree for a particular context */
|
|
void enterdelim(n)
|
|
int n;
|
|
{
|
|
if (! contree[n])
|
|
{
|
|
contree[n] = m_gettrienode();
|
|
}
|
|
|
|
if (m_ntrtrie(dstruct->string,
|
|
contree[n],
|
|
(void *) (unsigned long) dstruct->count))
|
|
{
|
|
char *mb_dstring, *mb_contexts;
|
|
|
|
mb_dstring = MakeMByteString(dstring);
|
|
mb_contexts = MakeMByteString(contexts[n]);
|
|
dcount--;
|
|
warning2("Duplicate assignment to delimiter \"%s\" in context \"%s\"",
|
|
mb_dstring,
|
|
mb_contexts);
|
|
m_free(mb_dstring,"multi-byte string");
|
|
m_free(mb_contexts,"multi-byte string");
|
|
}
|
|
}
|
|
|
|
/* Read the code to be executed with a given state transition */
|
|
void getcode(n)
|
|
int n;
|
|
{
|
|
int c ; /* c is int instead of char for use with ungetc */
|
|
int nested = 1;
|
|
LOGICAL comment = FALSE;
|
|
char *mb_context;
|
|
M_WCHAR wlb = 0, wcm, wnl, wsl, wst;
|
|
|
|
|
|
if (!wlb)
|
|
{
|
|
int
|
|
ret = mbtowc(&wlb, "{", 1); /* keep the "}" balanced */
|
|
ret = mbtowc(&wcm, ",", 1);
|
|
ret = mbtowc(&wnl, "\n", 1);
|
|
ret = mbtowc(&wsl, "/", 1);
|
|
ret = mbtowc(&wst, "*", 1);
|
|
(void) ret;
|
|
}
|
|
|
|
while (m_whitespace((M_WCHAR) (c = readchar(FALSE))));
|
|
if (c != wlb && c != wcm)
|
|
{
|
|
unread(c);
|
|
return;
|
|
}
|
|
|
|
if (! casestarted)
|
|
{
|
|
char *mb_dname;
|
|
|
|
mb_dname = MakeMByteString(dname);
|
|
casestarted = TRUE;
|
|
fprintf(fcase, " case %s:\n", mb_dname);
|
|
fprintf(fcase, " switch (m_prevcon) {\n") ; /* balance the } */
|
|
m_free(mb_dname,"multi-byte string");
|
|
}
|
|
|
|
mb_context = MakeMByteString(contexts[n]);
|
|
fprintf(fcase, " case %s:\n", mb_context);
|
|
m_free(mb_context,"multi-byte string");
|
|
|
|
if (c == wcm) return;
|
|
|
|
fprintf(fcase, "/* line %d \"context.dat\" */\n", m_line);
|
|
|
|
while (TRUE)
|
|
{
|
|
char mb_c[32]; /* arbitrarily large */
|
|
int length;
|
|
|
|
c = readchar(FALSE);
|
|
if (c == EOF)
|
|
{
|
|
warning("Unexpected EOF");
|
|
exit(TRUE);
|
|
}
|
|
|
|
length = wctomb(mb_c, c);
|
|
mb_c[length] = 0;
|
|
if (length == 1)
|
|
{
|
|
switch (mb_c[0])
|
|
{
|
|
case '{':
|
|
if (! comment) nested++;
|
|
break;
|
|
case '}':
|
|
if (! comment)
|
|
if (! --nested)
|
|
{
|
|
fprintf(fcase,"\n break ;\n");
|
|
return;
|
|
}
|
|
break;
|
|
case '/':
|
|
if (! comment)
|
|
{
|
|
fprintf(fcase, "/");
|
|
c = readchar(FALSE);
|
|
if (c == wst) comment = TRUE;
|
|
length = wctomb(mb_c, c);
|
|
mb_c[length] = 0;
|
|
}
|
|
break;
|
|
case '*':
|
|
if (comment)
|
|
{
|
|
fprintf(fcase, "*");
|
|
c = readchar(FALSE);
|
|
if (c == wsl) comment = FALSE;
|
|
length = wctomb(mb_c, c);
|
|
mb_c[length] = 0;
|
|
}
|
|
} /* End case */
|
|
}
|
|
fprintf(fcase, "%s", mb_c);
|
|
#if 0
|
|
if (c == wnl)
|
|
fprintf(fcase, "#line %d \"context.dat\"\n", m_line);
|
|
#endif
|
|
} /* End while */
|
|
} /* End proc getcode() */
|
|
|
|
/* Read the colon separating the two states in a transition pair */
|
|
void getcolon(void)
|
|
{
|
|
int c ; /* c is int instead of char for use with ungetc */
|
|
M_WCHAR wcl;
|
|
char unexp[32]; /* arbitraily large */
|
|
int length;
|
|
|
|
int ret = mbtowc(&wcl, ":", 1);
|
|
(void) ret;
|
|
|
|
while (TRUE)
|
|
{
|
|
c = readchar(FALSE);
|
|
if (! m_whitespace((M_WCHAR) c)) break;
|
|
}
|
|
if (c != wcl)
|
|
{
|
|
length = wctomb(unexp, (M_WCHAR) c);
|
|
unexp[length] = 0;
|
|
warning1("Expecting : instead of '%s'\n", unexp);
|
|
}
|
|
}
|
|
|
|
/* Read a context name from an input line */
|
|
int getContext(void)
|
|
{
|
|
M_WCHAR name[CNAMELEN + 1];
|
|
int c ; /* c is int instead of char for use with ungetc */
|
|
int i = 0;
|
|
M_WCHAR wsm = 0, wcl, wcm;
|
|
char *mb_name;
|
|
|
|
if (!wsm)
|
|
{
|
|
int
|
|
ret = mbtowc(&wsm, ";", 1);
|
|
ret = mbtowc(&wcl, ":", 1);
|
|
ret = mbtowc(&wcm, ",", 1);
|
|
(void) ret;
|
|
}
|
|
|
|
while (TRUE)
|
|
{
|
|
c = readchar(TRUE);
|
|
if (c == EOF) return(NOMORE);
|
|
*name = (M_WCHAR) c;
|
|
if (*name == wsm) return(NOMORE);
|
|
if (! m_whitespace(*name)) break;
|
|
}
|
|
|
|
while (TRUE)
|
|
{
|
|
i++;
|
|
if (i >= CNAMELEN)
|
|
{
|
|
while (! m_whitespace((M_WCHAR) (c = readchar(TRUE)))
|
|
&& c != wcl
|
|
&& c != wcm
|
|
&& c != EOF
|
|
&& c != wsm);
|
|
unread(c);
|
|
break;
|
|
}
|
|
c = readchar(TRUE);
|
|
if (m_whitespace((M_WCHAR) c) ||
|
|
c == wsm ||
|
|
c == wcl ||
|
|
c == wcm ||
|
|
c == EOF)
|
|
{
|
|
unread(c);
|
|
break;
|
|
}
|
|
name[i] = (M_WCHAR) c;
|
|
}
|
|
name[i] = M_EOS;
|
|
|
|
for (i = 0 ; i < ccount ; i++)
|
|
if (! w_strcmp(name, contexts[i])) return(i);
|
|
|
|
inccon() ;
|
|
i = w_strlen(name) + 1;
|
|
contexts[ccount - 1] = (M_WCHAR *) m_malloc(i, "context name");
|
|
memcpy(contexts[ccount - 1], name, i * sizeof(M_WCHAR));
|
|
|
|
mb_name = MakeMByteString(name);
|
|
fprintf(context, "#define %s %d\n", mb_name, ccount);
|
|
m_free(mb_name,"multi-byte string");
|
|
|
|
return(ccount - 1);
|
|
}
|
|
|
|
/* Read a delimiter name from the input line */
|
|
LOGICAL getdname(void)
|
|
{
|
|
int c;
|
|
M_WCHAR *p;
|
|
|
|
/* Skip leading blanks */
|
|
while (TRUE)
|
|
{
|
|
c = readchar(TRUE);
|
|
if (c == EOF) return(FALSE);
|
|
if (! m_whitespace((M_WCHAR) c)) break;
|
|
}
|
|
for (p = dname;
|
|
! m_whitespace((M_WCHAR) c) && c != EOF;
|
|
c = readchar(TRUE))
|
|
{
|
|
if (p - dname >= DNAMELEN)
|
|
{
|
|
while (! m_whitespace((M_WCHAR) c) && c != EOF) c = readchar(TRUE);
|
|
break;
|
|
}
|
|
*p++ = (M_WCHAR) c;
|
|
}
|
|
*p = M_EOS;
|
|
if ((dstruct = (struct dstruct *) m_lookfortrie(dname, &delimtrie)))
|
|
{
|
|
withdelim = TRUE;
|
|
curdelim = dstruct->count - 1;
|
|
}
|
|
else
|
|
{
|
|
char *mb_dname;
|
|
|
|
curdelim = dcount;
|
|
incdelim();
|
|
withdelim = FALSE;
|
|
mb_dname = MakeMByteString(dname);
|
|
fprintf(delim, "#define %s %d\n", mb_dname, dcount);
|
|
m_free(mb_dname,"multi-byte string");
|
|
}
|
|
return(TRUE);
|
|
}
|
|
|
|
/* Out of context space. Increase. */
|
|
void inccon(void)
|
|
{
|
|
M_TRIE **newtrie = NULL;
|
|
int *newtransit = NULL;
|
|
M_WCHAR **newcontexts = NULL;
|
|
int trysize;
|
|
int i, j;
|
|
|
|
if (ccount < NUMCON) {
|
|
ccount++;
|
|
return;
|
|
}
|
|
trysize = m_plus10p(NUMCON);
|
|
newtrie = (M_TRIE **) calloc(trysize, sizeof(M_TRIE *));
|
|
newtransit = (int *) calloc(trysize * NUMDELIM, sizeof(int));
|
|
newcontexts = (M_WCHAR **) calloc(trysize, sizeof(M_WCHAR *));
|
|
if (! newtrie || ! newtransit || ! newcontexts) {
|
|
trysize = NUMCON + 1;
|
|
if (newtrie) free((M_POINTER) newtrie);
|
|
if (newtransit) free((M_POINTER) newtransit);
|
|
if (newcontexts) free((M_POINTER) newcontexts);
|
|
newtrie = (M_TRIE **) calloc(trysize, sizeof(M_TRIE *));
|
|
newtransit = (int *) calloc(trysize * NUMDELIM, sizeof(int));
|
|
newcontexts = (M_WCHAR **) calloc(trysize, sizeof(M_WCHAR *));
|
|
}
|
|
if (! newtrie || ! newtransit || ! newcontexts) {
|
|
m_error("Out of memory for contexts");
|
|
exit(TRUE);
|
|
}
|
|
for (i = 0 ; i < ccount ; i++)
|
|
for (j = 0 ; j < dcount ; j++)
|
|
newtransit[i * NUMDELIM + j] = transit(i, j);
|
|
NUMCON = trysize;
|
|
free((M_POINTER) xtransit);
|
|
xtransit = newtransit;
|
|
memcpy((M_POINTER) newtrie, (M_POINTER) contree,
|
|
ccount * sizeof(M_TRIE **));
|
|
memcpy((M_POINTER) newcontexts, (M_POINTER) contexts,
|
|
ccount * sizeof(M_WCHAR **));
|
|
free((M_POINTER) contree);
|
|
free((M_POINTER) contexts);
|
|
contree = newtrie;
|
|
contexts = newcontexts;
|
|
ccount++;
|
|
}
|
|
|
|
/* Increase delimiter space. */
|
|
void incdelim(void)
|
|
{
|
|
int *newtransit = NULL;
|
|
char **newdlm = NULL;
|
|
int trysize;
|
|
int i, j;
|
|
|
|
if (dcount < NUMDELIM)
|
|
{
|
|
dcount++;
|
|
return;
|
|
}
|
|
|
|
trysize = m_plus10p(NUMDELIM);
|
|
newtransit = (int *) calloc(NUMCON * trysize, sizeof(int));
|
|
if (loading) newdlm = (char **) calloc(trysize, sizeof(M_WCHAR *));
|
|
if (! newtransit || (loading && ! newdlm))
|
|
{
|
|
trysize = NUMDELIM + 1;
|
|
free(newtransit);
|
|
newtransit = (int *) calloc(NUMCON * trysize, sizeof(int));
|
|
if (loading) { free(newdlm); newdlm = (char **) calloc(trysize, sizeof(M_WCHAR *)); }
|
|
}
|
|
if (! newtransit || (loading && ! newdlm))
|
|
{
|
|
m_error("Out of memory for delimiters");
|
|
exit(TRUE);
|
|
}
|
|
for (i = 0 ; i < ccount ; i++)
|
|
for (j = 0 ; j < dcount ; j++)
|
|
newtransit[i * trysize + j] = transit(i, j);
|
|
free((M_POINTER) xtransit);
|
|
if (loading)
|
|
{
|
|
memcpy((M_POINTER) newdlm, (M_POINTER) dlmptr, dcount * sizeof(M_TRIE **));
|
|
free((M_POINTER) dlmptr);
|
|
dlmptr = newdlm;
|
|
}
|
|
NUMDELIM = trysize;
|
|
xtransit = newtransit;
|
|
dcount++;
|
|
}
|
|
|
|
/* Read delimiter definitions from delim.dat */
|
|
void loaddelim(void)
|
|
{
|
|
int c;
|
|
M_WCHAR *p;
|
|
int i;
|
|
M_WCHAR wnl;
|
|
char *mb_dname, *mb_dstring;
|
|
|
|
int ret = mbtowc(&wnl, "\n", 1);
|
|
(void) ret;
|
|
|
|
loading = TRUE;
|
|
while ((c = getc(ddat)) != EOF)
|
|
{
|
|
/* Skip leading white space */
|
|
if (c == wnl) continue;
|
|
if (m_whitespace((M_WCHAR) c))
|
|
{
|
|
while ((c = getc(ddat)) != wnl)
|
|
if (c == EOF) return;
|
|
continue;
|
|
}
|
|
/* Delimiter name into dname */
|
|
for (p = dname ; ! m_whitespace((M_WCHAR) c) ; c = getc(ddat))
|
|
{
|
|
if (c == EOF)
|
|
{
|
|
warning("Unexpected EOF");
|
|
exit(TRUE);
|
|
}
|
|
if (p - dname >= DNAMELEN)
|
|
{
|
|
while (! m_whitespace((M_WCHAR) c) && c != EOF) c = getc(ddat);
|
|
if (c == EOF)
|
|
{
|
|
warning("Unexpected EOF");
|
|
exit(TRUE);
|
|
}
|
|
break;
|
|
}
|
|
*p++ = m_upper(c);
|
|
}
|
|
*p = M_EOS;
|
|
/* Skip intervening white space */
|
|
while (m_whitespace((M_WCHAR) c) && c != EOF) c = getc(ddat);
|
|
if (c == EOF)
|
|
{
|
|
warning("Unexpected EOF");
|
|
exit(TRUE);
|
|
}
|
|
/* Delimiter string into dstring */
|
|
for (p = dstring;
|
|
! m_whitespace((M_WCHAR) c) && c != EOF;
|
|
c = getc(ddat))
|
|
{
|
|
if (p - dstring >= DELIMLEN)
|
|
{
|
|
m_error("Delimiter string too long");
|
|
exit(TRUE);
|
|
}
|
|
*p++ = c;
|
|
}
|
|
*p = M_EOS;
|
|
if (w_strlen(dstring) > maxd) maxd = w_strlen(dstring);
|
|
/* Write definitions to output file. Save data for later. */
|
|
incdelim();
|
|
dstruct = (struct dstruct *)
|
|
m_malloc(sizeof(struct dstruct), "delimiter structure");
|
|
dstruct->string = (M_WCHAR *) m_malloc(w_strlen(dstring) + 1, "delimiter");
|
|
w_strcpy(dstruct->string, dstring);
|
|
dstruct->count = dcount;
|
|
|
|
mb_dname = MakeMByteString(dname);
|
|
fprintf(delim, "#define %s %d\n", mb_dname, dcount);
|
|
m_free(mb_dname,"multi-byte string");
|
|
|
|
for (i = 0 ; dname[i] ; i++)
|
|
dname[i] = m_lower(dname[i]);
|
|
mb_dname = MakeMByteString(dname);
|
|
|
|
mb_dstring = MakeMByteString(dstring);
|
|
fprintf(delim,
|
|
"M_DELIMEXTERN char %s[%d] M_DELIMINIT(\"",
|
|
mb_dname,
|
|
(int)strlen(mb_dstring) + 1);
|
|
|
|
for (p = dstring ; *p ; p++)
|
|
{
|
|
char *pc;
|
|
char mb_p[32]; /* arbitrarily large */
|
|
int length;
|
|
|
|
length = wctomb(mb_p, *p);
|
|
mb_p[length] = 0;
|
|
|
|
pc = mb_p;
|
|
while (*pc)
|
|
{
|
|
if (*pc == '"' || *pc == '\\') putc('\\', delim);
|
|
putc(*pc, delim);
|
|
pc++;
|
|
}
|
|
}
|
|
fputs("\") ;\n", delim);
|
|
|
|
dlmptr[dcount - 1] = MakeMByteString(dname);
|
|
if (m_ntrtrie(dname, &delimtrie, dstruct))
|
|
m_err1("Duplicate definition of %s", mb_dname);
|
|
while (c != wnl)
|
|
{
|
|
if (c == EOF) break;
|
|
c = getc(ddat);
|
|
}
|
|
m_free(mb_dname,"multi-byte string");
|
|
m_free(mb_dstring,"multi-byte string");
|
|
}
|
|
dumpdlmptr();
|
|
loading = FALSE;
|
|
}
|
|
|
|
/* Output transition matrix */
|
|
void nextcon(LOGICAL sparse)
|
|
{
|
|
int i, j;
|
|
int firstinrow;
|
|
|
|
if (sparse) {
|
|
for (i = 0 ; i < ccount ; i++) {
|
|
for (j = 0 ; j < dcount ; j++)
|
|
if (transit(i, j)) nonzero++;
|
|
nonzero++;
|
|
}
|
|
fprintf(delim,
|
|
"M_DELIMEXTERN struct {\n %s context ;\n %s nextcon ;\n",
|
|
contype, contype);
|
|
fprintf(delim, " } m_trnsit [%d]\n", nonzero);
|
|
|
|
nonzero = 0;
|
|
fprintf(delim, "#if defined(M_DELIMDEF)\n = {\n");
|
|
fprintf(context, "M_CONEXTERN int m_trnsptr[%d]\n", ccount);
|
|
fprintf(context, "#if defined(M_CONDEF)\n = {\n");
|
|
for (i = 0 ; i < ccount ; i++) {
|
|
firstinrow = 0;
|
|
for (j = 0 ; j < dcount ; j++) {
|
|
if (! transit(i, j)) continue;
|
|
prtctxt(j, transit(i, j));
|
|
if (! firstinrow) firstinrow = nonzero;
|
|
}
|
|
prtctxt(0, 0);
|
|
if (i > 0) fprintf(context, ",\n");
|
|
fprintf(context, " %d", firstinrow);
|
|
}
|
|
fprintf(delim, "%s", endif);
|
|
fprintf(context, "%s", endif);
|
|
}
|
|
else {
|
|
fprintf(context,
|
|
"M_CONEXTERN %s m_nextcon[%d][%d]\n#if defined(M_CONDEF)\n = {\n",
|
|
contype, ccount, dcount);
|
|
for (i = 0 ; i < ccount ; i++) {
|
|
fprintf(context, " {\n");
|
|
for (j = 0 ; j < dcount ; j++) {
|
|
fprintf(context, " %d", transit(i, j));
|
|
if (j < dcount - 1) fprintf(context, ",\n");
|
|
}
|
|
fprintf(context, "}");
|
|
if (i < ccount - 1) fprintf(context, ",");
|
|
fprintf(context, "\n");
|
|
}
|
|
fprintf(context, "%s", endif);
|
|
}
|
|
}
|
|
|
|
/* If sparse matrix output option, generate a single element of transit
|
|
array */
|
|
void prtctxt(column, value)
|
|
int column, value;
|
|
{
|
|
static LOGICAL first = TRUE;
|
|
|
|
if (! first) fprintf(delim, ",\n");
|
|
first = FALSE;
|
|
fprintf(delim, " {%d, %d}", column, value);
|
|
nonzero++;
|
|
}
|
|
|
|
|
|
/* Read the next input character */
|
|
int readchar(LOGICAL cap)
|
|
{
|
|
int c;
|
|
M_WCHAR wnl;
|
|
|
|
int ret = mbtowc(&wnl, "\n", 1);
|
|
(void) ret;
|
|
|
|
c = mb_getwc(cdat); /* use mb_getwc so we read multi-byte chars */
|
|
if (cap && c != EOF) c = m_upper(c);
|
|
|
|
if (c == wnl) m_line++;
|
|
|
|
return(c);
|
|
}
|
|
|
|
/* Called by utility procedure m_error() -- has content in other programs
|
|
that use m_error() */
|
|
void skiptoend(void)
|
|
{
|
|
}
|
|
|
|
/* Return a character to the input stream for re-reading */
|
|
void unread(c)
|
|
int c;
|
|
{
|
|
M_WCHAR wnl;
|
|
|
|
int ret = mbtowc(&wnl, "\n", 1);
|
|
(void) ret;
|
|
|
|
ungetc(c, cdat);
|
|
if (c == wnl) m_line--;
|
|
}
|