1/* errstr.c
2   Return a string for a uuconf error.
3
4   Copyright (C) 1992 Ian Lance Taylor
5
6   This file is part of the Taylor UUCP uuconf library.
7
8   This library is free software; you can redistribute it and/or
9   modify it under the terms of the GNU Library General Public License
10   as published by the Free Software Foundation; either version 2 of
11   the License, or (at your option) any later version.
12
13   This library is distributed in the hope that it will be useful, but
14   WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16   Library General Public License for more details.
17
18   You should have received a copy of the GNU Library General Public
19   License along with this library; if not, write to the Free Software
20   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307, USA.
21
22   The author of the program may be contacted at ian@airs.com.
23   */
24
25#include "uucnfi.h"
26
27#if USE_RCS_ID
28const char _uuconf_errstr_rcsid[] = "$Id: errstr.c,v 1.6 2002/03/05 19:10:42 ian Rel $";
29#endif
30
31static char *zeprint_num P((char *zbuf, size_t cbuf, int ival));
32
33/* Return an error string for a uuconf error.  This does not return a
34   uuconf error code, but instead returns the total buffer length.  */
35
36int
37uuconf_error_string (pglobal, ierr, zbuf, cbuf)
38     pointer pglobal;
39     int ierr;
40     char *zbuf;
41     size_t cbuf;
42{
43  struct sglobal *qglobal = (struct sglobal *) pglobal;
44  const char *zfile;
45  size_t cfile;
46  const char *zlineno;
47  char ablineno[100];
48  size_t clineno;
49  const char *zmsg;
50  char abmsg[100];
51  size_t cmsg;
52  const char *zerrno;
53  size_t cerrno;
54  size_t cret;
55  size_t ccopy;
56
57  /* The format of the message is
58
59     filename:lineno: message: errno
60
61     If there is no filename, the trailing colon is not output.  If
62     there is no linenumber, the trailing colon is not output.  If
63     there is no filename, the linenumber is not output, and neither
64     is the space before message.  If there is no errno, the
65     preceeding colon and space are not output.  */
66
67  /* Get the filename to put in the error message, if any.  */
68  if ((ierr & UUCONF_ERROR_FILENAME) == 0
69      || qglobal == NULL
70      || qglobal->zfilename == NULL)
71    {
72      zfile = "";
73      cfile = 0;
74    }
75  else
76    {
77      zfile = qglobal->zfilename;
78      cfile = strlen (zfile) + 1;
79    }
80
81  /* Get the line number to put in the error message, if any.  */
82  if (cfile == 0
83      || (ierr & UUCONF_ERROR_LINENO) == 0
84      || qglobal == NULL
85      || qglobal->ilineno <= 0)
86    {
87      zlineno = "";
88      clineno = 0;
89    }
90  else
91    {
92      zlineno = zeprint_num (ablineno, sizeof ablineno, qglobal->ilineno);
93      clineno = strlen (zlineno) + 1;
94    }
95
96  /* Get the main message.  */
97  switch (UUCONF_ERROR_VALUE (ierr))
98    {
99    case UUCONF_SUCCESS:
100      zmsg = "no error";
101      break;
102    case UUCONF_NOT_FOUND:
103      zmsg = "not found";
104      break;
105    case UUCONF_FOPEN_FAILED:
106      zmsg = "fopen";
107      break;
108    case UUCONF_FSEEK_FAILED:
109      zmsg = "fseek";
110      break;
111    case UUCONF_MALLOC_FAILED:
112      zmsg = "malloc";
113      break;
114    case UUCONF_SYNTAX_ERROR:
115      zmsg = "syntax error";
116      break;
117    default:
118      zmsg = zeprint_num (abmsg, sizeof abmsg, UUCONF_ERROR_VALUE (ierr));
119      zmsg -= sizeof "error " - 1;
120      memcpy ((pointer) zmsg, (pointer) "error ", sizeof "error " - 1);
121      break;
122    }
123
124  cmsg = strlen (zmsg);
125  if (cfile > 0)
126    ++cmsg;
127
128  /* Get the errno string.  Note that strerror is not necessarily
129     reentrant.  */
130  if ((ierr & UUCONF_ERROR_ERRNO) == 0
131      || qglobal == NULL)
132    {
133      zerrno = "";
134      cerrno = 0;
135    }
136  else
137    {
138      zerrno = strerror (qglobal->ierrno);
139      cerrno = strlen (zerrno) + 2;
140    }
141
142  cret = cfile + clineno + cmsg + cerrno + 1;
143
144  if (cbuf == 0)
145    return cret;
146
147  /* Leave room for the null byte.  */
148  --cbuf;
149
150  if (cfile > 0)
151    {
152      ccopy = cfile - 1;
153      if (ccopy > cbuf)
154	ccopy = cbuf;
155      memcpy ((pointer) zbuf, (pointer) zfile, ccopy);
156      zbuf += ccopy;
157      cbuf -= ccopy;
158      if (cbuf > 0)
159	{
160	  *zbuf++ = ':';
161	  --cbuf;
162	}
163    }
164
165  if (clineno > 0)
166    {
167      ccopy = clineno - 1;
168      if (ccopy > cbuf)
169	ccopy = cbuf;
170      memcpy ((pointer) zbuf, (pointer) zlineno, ccopy);
171      zbuf += ccopy;
172      cbuf -= ccopy;
173      if (cbuf > 0)
174	{
175	  *zbuf++ = ':';
176	  --cbuf;
177	}
178    }
179
180  if (cbuf > 0 && cfile > 0)
181    {
182      *zbuf++ = ' ';
183      --cbuf;
184      --cmsg;
185    }
186  ccopy = cmsg;
187  if (ccopy > cbuf)
188    ccopy = cbuf;
189  memcpy ((pointer) zbuf, (pointer) zmsg, ccopy);
190  zbuf += ccopy;
191  cbuf -= ccopy;
192
193  if (cerrno > 0)
194    {
195      if (cbuf > 0)
196	{
197	  *zbuf++ = ':';
198	  --cbuf;
199	}
200      if (cbuf > 0)
201	{
202	  *zbuf++ = ' ';
203	  --cbuf;
204	}
205      ccopy = cerrno - 2;
206      if (ccopy > cbuf)
207	ccopy = cbuf;
208      memcpy ((pointer) zbuf, (pointer) zerrno, ccopy);
209      zbuf += ccopy;
210      cbuf -= ccopy;
211    }
212
213  *zbuf = '\0';
214
215  return cret;
216}
217
218/* Turn a number into a string.  This should really call sprintf, but
219   since nothing else in the uuconf library calls any print routine,
220   it's more interesting to not call it here either.  */
221
222static char *
223zeprint_num (ab, c, i)
224     char *ab;
225     size_t c;
226     register int i;
227{
228  register char *z;
229
230  z = ab + c;
231  *--z = '\0';
232  do
233    {
234      *--z = i % 10 + '0';
235      i /= 10;
236    }
237  while (i != 0);
238
239  return z;
240}
241