4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
25 * sgsmsg generates several message files from an input template file. Messages
26 * are constructed for use with gettext(3i) - the default - or catgets(3c). The
29 * msg.h a header file containing definitions for each message. The -h
30 * option triggers the creation of these definitions and specifies
33 * msg.c a data array of message strings. The msg.h definitions are
34 * offsets into this array. The -d option triggers the creation of
35 * these definitions and specifies the name to use.
37 * messages a message file suitable for catgets(3c) or gettext(3i) use. The
38 * -m option triggers this output and specifies the filename to be
41 * The template file is processed based on the first character of each line:
43 * # or $ entries are copied (as is) to the message file (messages).
45 * @ token(s) entries are translated. Two translations are possible dependent
46 * on whether one or more tokens are supplied:
48 * A single token is interpreted as one of two reserved message
49 * output indicators, or a message identifier. The reserved output
50 * indicator _START_ enables output to the message file - Note that
51 * the occurance of any other @ token will also enable message
52 * output. The reserved output indicator _END_ disables output to
53 * the message file. The use of these two indicators provides for
54 * only those message strings that require translation to be output
55 * to the message file.
57 * Besides the reserved output indicators, a single token is taken
58 * to be a message identifier which will be subsituted for a
59 * `setid' for catgets(3c) output, or a `domain' name for
60 * gettext(3i) output. This value is determine by substituting the
61 * token for the associated definition found in the message
62 * identifier file (specified with the -i option).
64 * Multiple tokens are taken to be a message definition followed by
65 * the associated message string. The message string is copied to
66 * the data array being built in msg.c. The index into this array
67 * becomes the `message' identifier created in the msg.h file.
69 #pragma ident "%Z%%M% %I% %E% SMI"
79 #include <sys/param.h>
82 #include <_string_table.h>
85 * Define any error message strings.
88 * Errmsg_malt = "sgsmsg: file %s: line %d: malformed input "
90 * Errmsg_nmem = "sgsmsg: memory allocation failed: %s\n",
91 * Errmsg_opne = "sgsmsg: file %s: open failed: %s\n",
92 * Errmsg_wrte = "sgsmsg: file %s: write failed: %s\n",
93 * Errmsg_read = "sgsmsg: file %s: read failed %s\n",
94 * Errmsg_stnw = "sgsmsg: st_new(): failed: %s\n",
95 * Errmsg_stin = "sgsmsg: Str_tbl insert failed: %s\n",
96 * Errmsg_mnfn = "sgsmsg: message not found in Str_tbl: %s\n",
97 * Errmsg_use = "usage: sgsmsg [-clv] [-d mesgdata] [-h mesgdefs] "
98 "[-m messages] [-n name] [-i mesgident] file ...\n";
101 * Define all output filenames and associated descriptors.
103 static FILE *fddefs, *fddata, *fdmsgs, *fdmids, *fddesc;
104 static char *fldefs, *fldata, *flmsgs, *flmids, *fldesc;
106 static char fllint[MAXPATHLEN];
108 static uint_t vflag; /* verbose flag */
109 static Str_tbl *stp; /* string table */
112 * Define any default strings.
115 *nmlint = "/tmp/sgsmsg.lint",
116 *interface = "sgs_msg",
121 * Define any default flags and data items.
123 static int cflag = 0, lflag = 0, prtmsgs = 0, line, ptr = 1, msgid = 0;
124 static char *mesgid = 0, *setid = 0, *domain = 0;
126 typedef struct msg_string {
129 struct msg_string *ms_next;
132 static msg_string *msg_head;
133 static msg_string *msg_tail;
136 * message_append() is responsible for both inserting strings into
137 * the master Str_tbl as well as maintaining a list of the
138 * DEFINITIONS associated with each string.
140 * The list of strings is traversed at the end once the full
141 * Str_tbl has been constructed - and string offsets can be
145 message_append(const char *defn, const char *message)
148 if ((msg = calloc(sizeof (msg_string), 1)) == 0) {
149 (void) fprintf(stderr, Errmsg_nmem, strerror(errno));
154 * Initialize the string table.
156 if ((stp == 0) && ((stp = st_new(FLG_STNEW_COMPRESS)) == NULL)) {
157 (void) fprintf(stderr, Errmsg_stnw, strerror(errno));
162 if ((msg->ms_defn = strdup(defn)) == 0) {
163 (void) fprintf(stderr, Errmsg_nmem, strerror(errno));
166 if ((msg->ms_message = strdup(message)) == 0) {
167 (void) fprintf(stderr, Errmsg_nmem, strerror(errno));
171 if (st_insert(stp, msg->ms_message) == -1) {
172 (void) fprintf(stderr, Errmsg_stin,
178 msg_head = msg_tail = msg;
181 msg_tail->ms_next = msg;
186 * Initialize a setid value. Given a setid definition determine its numeric
187 * value from the specified message identifier file (specified with the -i
188 * option). Return a pointer to the numeric string.
193 char *buffer, *token, *_mesgid = 0, *_setid = 0, *_domain = 0;
196 * If we're being asked to interpret a message id but the user didn't
197 * provide the required message identifier file (-i option) we're in
201 (void) fprintf(stderr, "sgsmsg: file %s: line %d: mesgid %s: "
202 "unable to process mesgid\n\t"
203 "no message identifier file specified "
204 "(see -i option)\n", fldesc, line, id);
208 if ((buffer = malloc(LINE_MAX)) == 0) {
209 (void) fprintf(stderr, Errmsg_nmem, strerror(errno));
214 * Read the message identifier file and locate the required mesgid.
217 while (fgets(buffer, LINE_MAX, fdmids) != NULL) {
218 if ((token = strstr(buffer, id)) == NULL)
222 * Establish individual strings for the mesgid, setid and domain
226 while (!(isspace(*token)))
230 while (isspace(*token))
233 while (!(isspace(*token)))
237 while (isspace(*token))
240 while (!(isspace(*token)))
247 * Did we find a match?
249 if ((_mesgid == 0) || (_setid == 0) || (_domain == 0)) {
250 (void) fprintf(stderr, "sgsmsg: file %s: line %d: mesgid %s: "
251 "unable to process mesgid\n\t"
252 "identifier does not exist in file %s\n",
253 fldesc, line, id, flmids);
258 * Have we been here before?
263 * If we're being asked to process more than one mesgid
264 * warn the user that only one mesgid can be used for
265 * the catgets(3c) call.
267 (void) fprintf(stderr, "sgsmsg: file %s: line %d: "
268 "setid %s: warning: multiple mesgids "
270 "last setting used in messaging code\n",
280 * Generate the message file output (insure output flag is enabled).
284 if (fdmsgs && (prtmsgs == 1)) {
286 if (fprintf(fdmsgs, "$quote \"\n$set %s\n",
288 (void) fprintf(stderr, Errmsg_wrte, flmsgs,
293 if (fprintf(fdmsgs, "domain\t\"%s\"\n", domain) < 0) {
294 (void) fprintf(stderr, Errmsg_wrte, flmsgs,
302 * For catgets(3c) output generate a setid definition in the message
305 if (fddefs && (cflag == 1) &&
306 (fprintf(fddefs, "#define\t%s\t%s\n\n", mesgid, setid) < 0)) {
307 (void) fprintf(stderr, Errmsg_wrte, fldefs, strerror(errno));
315 * Dump contents of String Table to standard out
318 dump_stringtab(Str_tbl *stp)
322 if ((stp->st_flags & FLG_STTAB_COMPRESS) == 0) {
323 (void) printf("string table full size: %ld: uncompressed\n",
324 stp->st_fullstrsize);
328 (void) printf("string table full size: %ld compressed down to: %ld\n\n",
329 stp->st_fullstrsize, stp->st_strsize);
330 (void) printf("string table compression information [%d buckets]:\n",
333 for (cnt = 0; cnt < stp->st_hbckcnt; cnt++) {
334 Str_hash *sthash = stp->st_hashbcks[cnt];
339 (void) printf(" bucket: [%d]\n", cnt);
342 size_t stroff = sthash->hi_mstr->sm_strlen -
346 (void) printf(" [%ld]: '%s' <master>\n",
347 sthash->hi_refcnt, sthash->hi_mstr->sm_str);
349 (void) printf(" [%ld]: '%s' <suffix of: "
350 "'%s'>\n", sthash->hi_refcnt,
351 &sthash->hi_mstr->sm_str[stroff],
352 sthash->hi_mstr->sm_str);
354 sthash = sthash->hi_next;
360 * Initialize the message definition header file stream.
365 static char guard[FILENAME_MAX + 6];
367 const char *iptr, *_ptr;
370 * Establish a header guard name using the files basename.
372 for (iptr = 0, _ptr = fldefs; _ptr && (*_ptr != '\0'); _ptr++) {
380 for (*optr++ = '_'; iptr && (*iptr != '\0'); iptr++, optr++) {
388 *optr = toupper(*iptr);
391 if (fprintf(fddefs, "#ifndef\t%s\n#define\t%s\n\n", guard, guard) < 0) {
392 (void) fprintf(stderr, Errmsg_wrte, fldefs, strerror(errno));
396 if (fprintf(fddefs, "#ifndef\t__lint\n\n") < 0) {
397 (void) fprintf(stderr, Errmsg_wrte, fldefs, strerror(errno));
402 * add "typedef int Msg;"
404 if (fprintf(fddefs, "typedef int\tMsg;\n\n") < 0) {
405 (void) fprintf(stderr, Errmsg_wrte, fldefs, strerror(errno));
410 * If the associated data array is global define a prototype.
411 * Define a macro to access the array elements.
414 if (fprintf(fddefs, "extern\tconst char\t__%s[];\n\n",
416 (void) fprintf(stderr, Errmsg_wrte, fldefs,
421 if (fprintf(fddefs, "#define\tMSG_ORIG(x)\t&__%s[x]\n\n",
423 (void) fprintf(stderr, Errmsg_wrte, fldefs, strerror(errno));
428 * Generate a prototype to access the associated data array.
430 if (fprintf(fddefs, "extern\tconst char *\t_%s(Msg);\n\n",
432 (void) fprintf(stderr, Errmsg_wrte, fldefs, strerror(errno));
435 if (fprintf(fddefs, "#define\tMSG_INTL(x)\t_%s(x)\n\n",
437 (void) fprintf(stderr, Errmsg_wrte, fldefs, strerror(errno));
446 * Finish the message definition header file.
451 if (fprintf(fddefs, "\n#else\t/* __lint */\n\n") < 0) {
452 (void) fprintf(stderr, Errmsg_wrte, fldefs, strerror(errno));
457 * When __lint is defined, Msg is a char *. This allows lint to
458 * check our format strings against it's arguments.
460 if (fprintf(fddefs, "\ntypedef char *\tMsg;\n\n") < 0) {
461 (void) fprintf(stderr, Errmsg_wrte, fldefs, strerror(errno));
465 if (fprintf(fddefs, "extern\tconst char *\t_%s(Msg);\n\n",
467 (void) fprintf(stderr, Errmsg_wrte, fldefs, strerror(errno));
472 if (fprintf(fddefs, "extern\tconst char\t__%s[];\n\n",
474 (void) fprintf(stderr, Errmsg_wrte, fldefs,
481 "#define MSG_ORIG(x)\tx\n#define MSG_INTL(x)\tx\n") < 0) {
482 (void) fprintf(stderr, Errmsg_wrte, fldefs, strerror(errno));
487 * Copy the temporary lint defs file into the new header.
493 size = ftell(fdlint);
494 (void) rewind(fdlint);
496 if ((buf = malloc(size)) == 0) {
497 (void) fprintf(stderr, Errmsg_nmem, strerror(errno));
500 if (fread(buf, size, 1, fdlint) == 0) {
501 (void) fprintf(stderr, Errmsg_read, fllint,
505 if (fwrite(buf, size, 1, fddefs) == 0) {
506 (void) fprintf(stderr, Errmsg_wrte, fldefs,
513 if (fprintf(fddefs, "\n#endif\t/* __lint */\n") < 0) {
514 (void) fprintf(stderr, Errmsg_wrte, fldefs, strerror(errno));
518 if (fprintf(fddefs, "\n#endif\n") < 0) {
519 (void) fprintf(stderr, Errmsg_wrte, fldefs, strerror(errno));
527 * The entire messaging file has been scanned - and all strings have been
528 * inserted into the string_table. We can now walk the message queue
529 * and create the '#define <DEFN>' for each string - with the strings
530 * assigned offset into the string_table.
539 stbufsize = st_getstrtab_sz(stp);
540 if ((stbuf = malloc(stbufsize)) == 0) {
541 (void) fprintf(stderr, Errmsg_nmem, strerror(errno));
544 (void) st_setstrbuf(stp, stbuf, stbufsize);
545 for (msg = msg_head; msg; msg = msg->ms_next) {
547 if ((st_setstring(stp, msg->ms_message, &stoff)) == -1) {
548 (void) fprintf(stderr, Errmsg_mnfn, msg->ms_message);
551 if (fprintf(fddefs, "\n#define\t%s\t%ld\n",
552 msg->ms_defn, stoff) < 0) {
553 (void) fprintf(stderr, Errmsg_wrte,
554 fldefs, strerror(errno));
557 if (fddefs && fprintf(fddefs, "#define\t%s_SIZE\t%d\n",
558 msg->ms_defn, strlen(msg->ms_message)) < 0) {
559 (void) fprintf(stderr, Errmsg_wrte,
560 fldefs, strerror(errno));
569 * Finish off the data structure definition.
580 stbufsize = st_getstrtab_sz(stp);
581 stbuf = st_getstrbuf(stp);
586 * Determine from the local flag whether the data declaration should
590 fmtstr = (const char *)"static const";
592 fmtstr = (const char *)"const";
594 if (fprintf(fddata, "\n%s char __%s[%ld] = { ",
595 fmtstr, interface, stbufsize) < 0) {
596 (void) fprintf(stderr, Errmsg_wrte, fldata, strerror(errno));
600 for (ndx = 0; ndx < (stbufsize - 1); ndx++) {
602 if (fddata && fprintf(fddata,
603 "\n/* %4ld */ 0x%.2x,", ndx,
604 (unsigned char)stbuf[ndx]) < 0) {
605 (void) fprintf(stderr, Errmsg_wrte,
606 fldata, strerror(errno));
610 if (fddata && fprintf(fddata, " 0x%.2x,",
611 (unsigned char)stbuf[ndx]) < 0) {
612 (void) fprintf(stderr, Errmsg_wrte,
613 fldata, strerror(errno));
623 fmtstr = "\n\t0x%.2x };\n";
625 fmtstr = " 0x%.2x };\n";
627 if (fprintf(fddata, fmtstr, (unsigned char)stbuf[stbufsize - 1]) < 0) {
628 (void) fprintf(stderr, Errmsg_wrte, fldata, strerror(errno));
638 char buffer[LINE_MAX], * token;
643 if ((token_buffer = malloc(LINE_MAX)) == 0) {
644 (void) fprintf(stderr, Errmsg_nmem, strerror(errno));
651 while ((token = fgets(buffer, LINE_MAX, fddesc)) != NULL) {
652 char defn[PATH_MAX], * _defn, * str;
659 (void) fprintf(stderr, Errmsg_malt, fldesc,
665 * If a msgid has been output a msgstr must follow
666 * before we digest the new token. A msgid is only set
667 * if fdmsgs is in use.
671 if (fprintf(fdmsgs, "msgstr\t\"\"\n") < 0) {
672 (void) fprintf(stderr, Errmsg_wrte,
673 flmsgs, strerror(errno));
679 * Pass lines directly through to the output message
682 if (fdmsgs && (prtmsgs == 1)) {
690 if (fprintf(fdmsgs, "%c%s", comment,
692 (void) fprintf(stderr, Errmsg_wrte,
693 flmsgs, strerror(errno));
701 (void) fprintf(stderr, Errmsg_malt, fldesc,
707 * If a msgid has been output a msgstr must follow
708 * before we digest the new token.
712 if (fprintf(fdmsgs, "msgstr\t\"\"\n") < 0) {
713 (void) fprintf(stderr, Errmsg_wrte,
714 flmsgs, strerror(errno));
720 * Determine whether we have one or more tokens.
723 while (isspace(*token)) /* rid any whitespace */
725 _defn = token; /* definition start */
726 while (!(isspace(*token)))
730 while (isspace(*token)) /* rid any whitespace */
734 * Determine whether the single token is one of the
735 * reserved message output delimiters otherwise
736 * translate it as a message identifier.
739 if (strcmp(_defn, start) == 0)
741 else if (strcmp(_defn, end) == 0)
743 else if (getmesgid(_defn) == 1)
749 * Multiple tokens are translated by taking the first
750 * token as the message definition, and the rest of the
751 * line as the message itself. A message line ending
752 * with an escape ('\') is expected to be continued on
757 if (fdmsgs && (prtmsgs == 1)) {
759 * For catgets(3c) make sure a message
760 * identifier has been established (this is
761 * normally a domain for gettext(3i), but for
762 * sgsmsg use this could be argued as being
763 * redundent). Also make sure that the message
764 * definitions haven't exceeeded the maximum
765 * value allowed by gencat(1) before generating
766 * any message file entries.
770 (void) fprintf(stderr, "file "
771 "%s: no message identifier "
772 "has been established\n",
776 if (ptr > NL_MSGMAX) {
777 (void) fprintf(stderr, "file "
778 "%s: message definition "
779 "(%d) exceeds allowable "
780 "limit (NL_MSGMAX)\n",
787 * For catgets(3c) write the definition and the
788 * message string to the message file. For
789 * gettext(3i) write the message string as a
790 * mesgid - indicate a mesgid has been output
791 * so that a msgstr can follow.
794 if (fprintf(fdmsgs, "%d\t%s", ptr,
796 (void) fprintf(stderr,
802 if (fprintf(fdmsgs, "msgid\t\"") < 0) {
803 (void) fprintf(stderr,
813 * The message itself is a quoted string as this makes
814 * embedding spaces at the start (or the end) of the
818 (void) fprintf(stderr, Errmsg_malt, fldesc,
823 (void) strcpy(defn, _defn);
826 * Write the tag to the lint definitions.
829 if (fprintf(fdlint, "\n#define\t%s\t",
831 (void) fprintf(stderr, Errmsg_wrte,
832 fllint, strerror(errno));
840 * Write each character of the message string to the
841 * data array. Translate any escaped characters - use
842 * the same specially recognized characters as defined
848 (fprintf(fdlint, "%c", *token) < 0)) {
849 (void) fprintf(stderr, Errmsg_wrte,
850 fllint, strerror(errno));
858 if ((*token == '\\') && (escape == 0)) {
860 if (fdlint && (*(token + 1) != '\n') &&
861 fprintf(fdlint, "%c", *token) < 0) {
862 (void) fprintf(stderr,
873 else if (*token == 't')
875 else if (*token == 'v')
877 else if (*token == 'b')
879 else if (*token == 'f')
881 else if (*token == '\\')
883 else if (*token == '"')
885 else if (*token == '\n')
890 if (fdmsgs && (prtmsgs == 1) &&
891 (fprintf(fdmsgs, "\\") < 0)) {
892 (void) fprintf(stderr,
899 * If this is the trailing quote then
900 * thats the last of the message string.
901 * Eat up any remaining white space and
902 * unless an escape character is found
903 * terminate the data string with a 0.
907 if (fdlint && (fprintf(fdlint,
908 "%c", *token) < 0)) {
909 (void) fprintf(stderr,
915 if (fdmsgs && (prtmsgs == 1) &&
916 (fprintf(fdmsgs, "%c",
918 (void) fprintf(stderr,
934 if (fdmsgs && (prtmsgs == 1) &&
935 (fprintf(fdmsgs, "%c", *token) < 0)) {
936 (void) fprintf(stderr, Errmsg_wrte,
937 flmsgs, strerror(errno));
941 if (fdlint && fprintf(fdlint,
943 (void) fprintf(stderr, Errmsg_wrte,
944 fllint, strerror(errno));
948 if (len >= bufsize) {
950 if ((token_buffer = realloc(
951 token_buffer, bufsize)) == 0) {
952 (void) fprintf(stderr,
958 token_buffer[len] = _token;
959 ptr++, token++, len++;
967 * After the complete message string has been processed
968 * (including its continuation beyond one line), create
969 * a string size definition.
972 const char *form = "#define\t%s_SIZE\t%d\n";
974 token_buffer[len] = '\0';
976 message_append(defn, token_buffer);
978 if (fdlint && fprintf(fdlint, form, defn,
980 (void) fprintf(stderr, Errmsg_wrte,
981 fllint, strerror(errno));
989 * Empty lines are passed through to the message file.
991 while (isspace(*token))
995 if (msgid || (fdmsgs && (prtmsgs == 1))) {
997 * If a msgid has been output a msgstr
998 * must follow before we digest the new
1003 str = "msgstr\t\"\"\n\n";
1007 if (fprintf(fdmsgs, str) < 0) {
1008 (void) fprintf(stderr,
1009 Errmsg_wrte, flmsgs,
1018 * If an escape is in effect then any tokens are taken
1019 * to be message continuations.
1026 (void) fprintf(stderr, "file %s: line %d: invalid "
1027 "input does not start with #, $ or @\n", fldesc,
1040 main(int argc, char ** argv)
1043 while ((line = getopt(argc, argv, "cd:h:lm:n:i:v")) != EOF) {
1045 case 'c': /* catgets instead of gettext */
1048 case 'd': /* new message data filename */
1049 fldata = optarg; /* (msg.c is default) */
1051 case 'h': /* new message defs filename */
1052 fldefs = optarg; /* (msg.h is default) */
1054 case 'i': /* input message ids from */
1055 flmids = optarg; /* from this file */
1057 case 'l': /* define message data arrays */
1058 lflag = 1; /* to be local (static) */
1060 case 'm': /* generate message database */
1061 flmsgs = optarg; /* to this file */
1063 case 'n': /* new data array and func */
1064 interface = optarg; /* name (msg is default) */
1067 vflag = 1; /* set verbose flag */
1070 (void) fprintf(stderr, Errmsg_use, argv[0]);
1078 * Validate the we have been given at least one input file.
1080 if ((argc - optind) < 1) {
1081 (void) fprintf(stderr, Errmsg_use);
1086 * Open all the required output files.
1089 if ((fddefs = fopen(fldefs, "w+")) == NULL) {
1090 (void) fprintf(stderr, Errmsg_opne, fldefs,
1096 if (fldefs && (strcmp(fldefs, fldata) == 0))
1098 else if ((fddata = fopen(fldata, "w+")) == NULL) {
1099 (void) fprintf(stderr, Errmsg_opne, fldata,
1104 if (fddefs && fddata) {
1105 (void) sprintf(fllint, "%s.%d", nmlint, (int)getpid());
1106 if ((fdlint = fopen(fllint, "w+")) == NULL) {
1107 (void) fprintf(stderr, Errmsg_opne, fllint,
1113 if ((fdmsgs = fopen(flmsgs, "w+")) == NULL) {
1114 (void) fprintf(stderr, Errmsg_opne, flmsgs,
1120 if ((fdmids = fopen(flmids, "r")) == NULL) {
1121 (void) fprintf(stderr, Errmsg_opne, flmids,
1129 * Initialize the message definition and message data streams.
1137 * Read the input message file, and for each line process accordingly.
1139 for (; optind < argc; optind++) {
1142 fldesc = argv[optind];
1144 if ((fddesc = fopen(fldesc, "r")) == NULL) {
1145 (void) fprintf(stderr, Errmsg_opne, fldesc,
1150 (void) fclose(fddesc);
1157 * If a msgid has been output a msgstr must follow before we end the
1162 if (fprintf(fdmsgs, "msgstr\t\"\"\n") < 0) {
1163 (void) fprintf(stderr, Errmsg_wrte, flmsgs,
1170 (void) fclose(fdmids);
1172 (void) fclose(fdmsgs);
1180 * Finish off any generated data and header file.
1192 dump_stringtab(stp);
1195 * Close up everything and go home.
1198 (void) fclose(fddata);
1199 if (fddefs && (fddefs != fddata))
1200 (void) fclose(fddefs);
1201 if (fddefs && fddata) {
1202 (void) fclose(fdlint);
1203 (void) unlink(fllint);