1 /* Database interface library.
2 * - by Richard W.M. Jones <rich@annexia.org>
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the Free
16 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 * $Id: pthr_dbi.c,v 1.18 2003/06/17 18:10:30 rich Exp $
36 #ifdef HAVE_POSTGRESQL_LIBPQ_FE_H
37 #include <postgresql/libpq-fe.h>
40 #ifdef HAVE_LIBPQ_FE_H
44 #ifndef HAVE_PQESCAPESTRING
45 size_t PQescapeString(char *to, const char *from, size_t length);
54 #include "pthr_pseudothread.h"
57 #define DBI_FORCE_DEBUG 0
58 #define DBI_POOLS_DEBUG 0
60 #define DEBUG(dbh,sth,fs,args...) do { if (DBI_FORCE_DEBUG || ((dbh)->flags & DBI_DEBUG)) { if ((sth) == 0) fprintf (stderr, "dbi: dbh %p: " fs, (dbh) , ## args); else fprintf (stderr, "dbi: dbh %p sth %p: " fs, (dbh), (void *) (sth) , ## args); fputc ('\n', stderr); } } while (0)
62 /* Database handle. */
65 pool pool; /* Pool for allocations. */
66 const char *conninfo; /* Connection string. */
67 int flags; /* Flags. */
68 int in_transaction; /* Are we in a transaction yet? */
69 PGconn *conn; /* The database connection object. */
72 /* Statement handle. */
75 pool pool; /* Subpool used for allocations. */
76 db_handle dbh; /* Parent database connection. */
77 const char *orig_query; /* Original query string. */
78 vector query; /* Query, split into string, '?' and '@'. */
79 vector intypes; /* Placeholder types (vector of int). */
80 PGresult *result; /* Last result. */
81 int fetch_allowed; /* True if there are tuples to fetch. */
82 int next_tuple; /* Next row to fetch. */
83 vector outtypes; /* Output types (vector of struct otype). */
88 int type; /* Type of this element. */
89 void *varptr; /* Pointer to variable for result. */
92 static void init_dbi (void) __attribute__((constructor));
93 static void free_dbi (void) __attribute__((destructor));
94 static void disconnect (void *vdbh);
95 static void parse_timestamp (st_handle sth, const char *str, struct dbi_timestamp *ts);
96 static void parse_interval (st_handle sth, const char *str, struct dbi_interval *inv);
98 /* Global variables. */
100 static const pcre *re_qs, *re_timestamp, *re_interval;
102 /* For connection pools. */
103 static shash connpools; /* Hash conninfo string -> vector of dbh. */
104 static hash inuse; /* Hash dbh -> subpool, of handles in use. */
106 /* Initialise the library. */
111 dbi_pool = new_subpool (global_pool);
113 dbi_pool = new_pool ();
115 re_qs = precomp (dbi_pool, "\\?|@", 0);
116 re_timestamp = precomp (dbi_pool,
117 " (?:(\\d\\d\\d\\d)-(\\d\\d)-(\\d\\d)) # date (YYYY-MM-DD)\n"
118 " \\s* # space between date and time\n"
119 " (?:(\\d\\d):(\\d\\d) # HH:MM\n"
120 " (?::(\\d\\d))? # optional :SS\n"
121 " (?:\\.(\\d+))? # optional .microseconds\n"
122 " (?:([+-])(\\d\\d))? # optional +/-OO offset from UTC\n"
123 " )?", PCRE_EXTENDED);
124 re_interval = precomp (dbi_pool,
125 " (?:(\\d+)\\syears?)? # years\n"
127 " (?:(\\d+)\\smons?)? # months\n"
129 " (?:(\\d+)\\sdays?)? # days\n"
131 " (?:(\\d\\d):(\\d\\d) # HH:MM\n"
132 " (?::(\\d\\d))? # optional :SS\n"
133 " )?", PCRE_EXTENDED);
135 /* Set up connection pools. */
136 connpools = new_shash (dbi_pool, vector);
137 inuse = new_hash (dbi_pool, db_handle, pool);
140 /* Free up global memory used by the library. */
144 delete_pool (dbi_pool);
148 new_db_handle (pool pool, const char *conninfo, int flags)
150 db_handle dbh = pmalloc (pool, sizeof *dbh);
154 dbh->conninfo = pstrdup (pool, conninfo);
156 dbh->in_transaction = 0;
158 /* Begin the database connection. */
159 dbh->conn = PQconnectStart (conninfo);
160 if (dbh->conn == 0) /* Failed. */
163 /* See the PostgreSQL documentation for the libpq connect functions
164 * for details about how the following loop works.
166 status = PQstatus (dbh->conn);
167 if (status == CONNECTION_BAD)
169 PQfinish (dbh->conn);
170 return 0; /* Connection failed immediately. */
173 if (PQsetnonblocking (dbh->conn, 1) == -1) abort ();
174 fd = PQsocket (dbh->conn);
176 status = PGRES_POLLING_WRITING;
178 while (status != PGRES_POLLING_OK &&
179 status != PGRES_POLLING_FAILED)
183 case PGRES_POLLING_WRITING:
184 pth_wait_writable (fd);
186 case PGRES_POLLING_READING:
187 pth_wait_readable (fd);
190 status = PQconnectPoll (dbh->conn);
193 if (status == PGRES_POLLING_FAILED)
195 PQfinish (dbh->conn);
196 return 0; /* Connection failed. */
201 DEBUG (dbh, 0, "connected");
203 /* Remember to clean up this connection when the pool gets deleted. */
204 pool_register_cleanup_fn (dbh->pool, disconnect, dbh);
210 disconnect (void *vdbh)
212 db_handle dbh = (db_handle) vdbh;
214 PQfinish (dbh->conn);
216 DEBUG (dbh, 0, "disconnected");
220 db_set_debug (db_handle dbh, int d)
224 dbh->flags |= DBI_DEBUG;
225 DEBUG (dbh, 0, "debugging enabled");
229 DEBUG (dbh, 0, "debugging disabled");
230 dbh->flags &= ~DBI_DEBUG;
235 db_get_debug (db_handle dbh)
237 return dbh->flags & DBI_DEBUG;
241 db_commit (db_handle dbh)
245 sth = st_prepare_cached (dbh, "commit work");
248 dbh->in_transaction = 0;
252 db_rollback (db_handle dbh)
256 sth = st_prepare_cached (dbh, "rollback work");
259 dbh->in_transaction = 0;
263 db_in_transaction (db_handle dbh)
265 return dbh->in_transaction;
268 static void return_dbh (void *vdbh);
271 get_db_handle (const char *conninfo, int flags)
277 /* Allocate a subpool of the current thread's pool. If the thread dies
278 * or if the thread calls put_db_handle, this subpool will be deleted,
279 * resulting in the return_dbh function being called.
281 pool = new_subpool (pth_get_pool (current_pth));
283 /* Get a free handle. */
284 if (shash_get (connpools, conninfo, free_dbhs) &&
285 vector_size (free_dbhs) > 0)
287 /* Push back, pop front to ensure handles are circulated and used
290 vector_pop_front (free_dbhs, dbh);
293 assert (strcmp (dbh->conninfo, conninfo) == 0);
296 if (!dbh) /* Need to create a new handle. */
297 dbh = new_db_handle (dbi_pool, conninfo, flags);
299 /* Remember to return this handle when the subpool is deleted. */
300 pool_register_cleanup_fn (pool, return_dbh, dbh);
302 /* Remember this handle is in use. */
303 hash_insert (inuse, dbh, pool);
306 fprintf (stderr, "get_db_handle: conninfo \"%s\" -> dbh %p\n",
314 put_db_handle (db_handle dbh)
319 fprintf (stderr, "put_db_handle: dbh %p (conninfo \"%s\")\n",
323 /* Find the corresponding subpool and delete it. */
324 if (!hash_get (inuse, dbh, pool)) abort ();
328 /* This function is called when the thread exits or calls put_db_handle. We
329 * need to return this handle to the correct connection pool.
332 return_dbh (void *vdbh)
334 db_handle dbh = (db_handle) vdbh;
338 fprintf (stderr, "return_dbh: dbh %p (conninfo \"%s\")\n",
342 if (dbh->in_transaction) db_rollback (dbh);
344 /* Remove from the in-use list. */
345 if (!hash_erase (inuse, dbh)) abort ();
347 if (shash_get (connpools, dbh->conninfo, free_dbhs))
348 vector_push_back (free_dbhs, dbh);
351 /* Need to create the free dbhs vector. */
352 free_dbhs = new_vector (dbi_pool, db_handle);
353 vector_push_back (free_dbhs, dbh);
354 shash_insert (connpools, dbh->conninfo, free_dbhs);
359 st_serial (st_handle sth, const char *seq_name)
361 db_handle dbh = sth->dbh;
365 /* In PostgreSQL, to fetch the serial number we need to issue another
366 * command to the database.
368 sth2 = st_prepare_cached (dbh, "select currval (?)", DBI_STRING);
369 st_execute (sth2, seq_name);
371 st_bind (sth2, 0, serial, DBI_INT);
373 if (!st_fetch (sth2))
375 if ((dbh->flags & DBI_THROW_ERRORS))
376 pth_die ("dbi: st_serial: failed to fetch sequence value");
384 static void finish_handle (void *vsth);
387 new_st_handle (db_handle dbh, const char *query, int flags, ...)
394 /* XXX Ignore the caching flag at the moment. Statement handles cannot
395 * be trivially cached, because the same handle might then be used
396 * concurrently in two different threads, which would cause serious
397 * problems. Also since PostgreSQL doesn't support PREPARE yet, we
398 * don't get the particular performance boost by caching query plans
399 * on the server side anyway.
401 * Actually the first statement isn't strictly true. We should never
402 * be sharing database handles across threads, so as long as we only
403 * cache statements in the database handle, we ought to be OK.
405 * (And the second statement isn't true anymore either - since 7.3,
406 * PostgreSQL supports PREPAREd statements).
409 /* Allocating in a subpool isn't strictly necessary at the moment. However
410 * in the future it will allow us to safely free up the memory associated
411 * with the statement handle when the handle is 'finished'.
413 pool = new_subpool (dbh->pool);
414 sth = pmalloc (pool, sizeof *sth);
418 sth->orig_query = query;
420 sth->fetch_allowed = 0;
423 /* Examine the query string looking for ? and @ placeholders which
424 * don't occur inside strings.
425 * XXX Haven't implemented the test for placeholders inside strings
426 * yet, so avoid using ? and @ as anything but placeholders for the
429 sth->query = pstrresplit2 (pool, query, re_qs);
431 /* Set up the array of input types. */
432 sth->intypes = new_vector (pool, int);
433 va_start (args, flags);
435 for (i = 0; i < vector_size (sth->query); ++i)
439 vector_get (sth->query, i, q);
441 if (strcmp (q, "?") == 0 || strcmp (q, "@") == 0)
443 int type = va_arg (args, int);
445 assert (DBI_MIN_TYPE <= type && type <= DBI_MAX_TYPE);
446 vector_push_back (sth->intypes, type);
452 /* Remember to clean up this handle when the pool gets deleted. */
453 pool_register_cleanup_fn (pool, finish_handle, sth);
455 DEBUG (dbh, sth, "handle created for query: %s", sth->orig_query);
461 finish_handle (void *vsth)
463 st_handle sth = (st_handle) vsth;
466 PQclear (sth->result);
469 DEBUG (sth->dbh, sth, "finished (implicit)");
472 static int exec_error (st_handle sth, PGresult *result);
473 static char *escape_string (pool, const char *);
476 st_execute (st_handle sth, ...)
478 pool pool = sth->pool;
485 ExecStatusType status;
487 /* Formulate a query with the types substituted as appropriate. */
488 query = pstrdup (pool, "");
489 va_start (args, sth);
491 for (i = 0, typeidx = 0; i < vector_size (sth->query); ++i)
496 vector_get (sth->query, i, q);
498 if (strcmp (q, "?") == 0) /* Simple placeholder. */
500 vector_get (sth->intypes, typeidx, type); typeidx++;
505 query = pstrcat (pool, query, pitoa (pool, va_arg (args, int)));
508 case DBI_INT_OR_NULL:
510 int r = va_arg (args, int);
513 query = pstrcat (pool, query, pitoa (pool, r));
515 query = pstrcat (pool, query, "null");
521 const char *str = va_arg (args, const char *);
525 query = pstrcat (pool, query, "'");
526 query = pstrcat (pool, query, escape_string (pool, str));
527 query = pstrcat (pool, query, "'");
530 query = pstrcat (pool, query, "null");
536 pstrcat (pool, query, va_arg (args, int) ? "'t'" : "'f'");
541 char str[2] = { va_arg (args, int), '\0' }; /* sic */
543 query = pstrcat (pool, query, "'");
544 query = pstrcat (pool, query, escape_string (pool, str));
545 query = pstrcat (pool, query, "'");
551 abort (); /* Not implemented yet! */
557 else if (strcmp (q, "@") == 0) /* List placeholder. */
561 vector_get (sth->intypes, typeidx, type); typeidx++;
563 /* We don't know yet if v is a vector of int or char *. */
564 v = va_arg (args, vector);
566 /* But we _do_ know that if the vector is empty, PG will fail.
567 * Stupid bug in PostgreSQL.
569 assert (vector_size (v) > 0);
574 v = pvitostr (pool, v);
575 query = pstrcat (pool, query, pjoin (pool, v, ","));
579 /* XXX Does not handle nulls correctly. */
580 query = pstrcat (pool, query, "'");
581 query = pstrcat (pool, query,
583 pmap (pool, v, escape_string), "','"));
584 query = pstrcat (pool, query, "'");
589 case DBI_INT_OR_NULL:
592 abort (); /* Not implemented yet! */
599 query = pstrcat (pool, query, q);
604 /* In transaction? If not, we need to issue a BEGIN WORK command. */
605 if (!sth->dbh->in_transaction)
609 /* So we don't go into infinite recursion here ... */
610 sth->dbh->in_transaction = 1;
612 sth_bw = st_prepare_cached (sth->dbh, "begin work");
613 if (st_execute (sth_bw) == -1)
615 sth->dbh->in_transaction = 0;
616 return exec_error (sth, 0);
620 DEBUG (sth->dbh, sth, "execute: %s", query);
622 /* Get the connection. */
623 conn = sth->dbh->conn;
624 assert (PQisnonblocking (conn));
625 fd = PQsocket (conn);
628 if (PQsendQuery (conn, query) != 1)
629 return exec_error (sth, 0);
631 /* Get all the command results. Ignore all but the last one. */
634 /* Wait for the result. */
635 while (PQisBusy (conn))
638 if (PQflush (conn) == EOF)
639 return exec_error (sth, 0);
641 pth_wait_readable (fd);
643 if (PQconsumeInput (conn) != 1)
644 return exec_error (sth, 0);
647 result = PQgetResult (conn);
650 if (sth->result) PQclear (sth->result);
651 sth->result = result;
656 /* Get the result status. */
657 status = PQresultStatus (sth->result);
659 if (status == PGRES_COMMAND_OK) /* INSERT, UPDATE, DELETE, etc. */
661 char *s = PQcmdTuples (sth->result);
664 sth->fetch_allowed = 0;
666 if (s && strlen (s) > 0 && sscanf (s, "%d", &rv) == 1)
667 return rv; /* Return rows affected. */
669 return 0; /* Command OK, unknown # rows affected. */
671 else if (status == PGRES_TUPLES_OK)
673 sth->fetch_allowed = 1;
676 /* SELECT OK, return number of rows in the result. */
677 return PQntuples (sth->result);
680 /* Some other error. */
681 return exec_error (sth, sth->result);
685 escape_string (pool pool, const char *s)
687 int len = strlen (s);
688 char *r = pmalloc (pool, len * 2 + 1);
690 PQescapeString (r, s, len);
695 exec_error (st_handle sth, PGresult *result)
697 if (!result) /* Some sort of connection-related error. */
699 perror ("dbi: st_execute: database connection error");
700 if ((sth->dbh->flags & DBI_THROW_ERRORS))
701 pth_die ("dbi: st_execute: database execution error");
705 else /* Execution error. */
707 char *error = psprintf (sth->pool,
708 "dbi: st_execute: %s",
709 PQresultErrorMessage (result));
711 fprintf (stderr, "%s\n", error);
712 if ((sth->dbh->flags & DBI_THROW_ERRORS))
720 _st_bind (st_handle sth, int colidx, void *varptr, int type)
722 struct otype zero = { 0, 0 };
726 if (sth->outtypes == 0)
727 sth->outtypes = new_vector (sth->pool, struct otype);
729 /* Is the vector large enough? If not, extend it. */
730 extend_by = colidx - vector_size (sth->outtypes) + 1;
732 vector_fill (sth->outtypes, zero, extend_by);
736 vector_replace (sth->outtypes, colidx, ot);
740 st_fetch (st_handle sth)
745 if (!sth->result || !sth->fetch_allowed)
748 "dbi: st_fetch: fetch without execute, or on a non-SELECT statement";
750 fprintf (stderr, "%s\n", error);
751 if ((sth->dbh->flags & DBI_THROW_ERRORS))
757 /* Get number of rows in the result. */
758 nr_rows = PQntuples (sth->result);
760 if (sth->next_tuple >= nr_rows)
762 DEBUG (sth->dbh, sth, "fetch: no more rows in query");
763 return 0; /* Finished. */
766 DEBUG (sth->dbh, sth, "fetch: starting row fetch");
770 for (i = 0; i < vector_size (sth->outtypes); ++i)
772 vector_get (sth->outtypes, i, ot);
774 if (ot.type != 0 && ot.varptr != 0)
776 int is_null = PQgetisnull (sth->result, sth->next_tuple, i);
777 char *r = !is_null ? PQgetvalue (sth->result, sth->next_tuple, i)
780 DEBUG (sth->dbh, sth, "fetch: col %d: %s", i, r);
785 * (char **) ot.varptr = r;
789 case DBI_INT_OR_NULL:
791 * (int *) ot.varptr = 0; /* Best we can do in C ! */
793 sscanf (r, "%d", (int *) ot.varptr);
798 * (int *) ot.varptr = 0; /* Best we can do! */
800 * (int *) ot.varptr = strcmp (r, "t") == 0;
805 * (char *) ot.varptr = 0; /* Best we can do! */
807 * (char *) ot.varptr = r[0];
812 struct dbi_timestamp *ts =
813 (struct dbi_timestamp *) ot.varptr;
815 memset (ts, 0, sizeof *ts);
819 parse_timestamp (sth, r, ts);
825 struct dbi_interval *inv =
826 (struct dbi_interval *) ot.varptr;
828 memset (inv, 0, sizeof *inv);
832 parse_interval (sth, r, inv);
842 DEBUG (sth->dbh, sth, "fetch: ended row fetch");
846 return 1; /* Row returned. */
850 parse_fixed_width_int (const char *str, int width)
854 for (i = 0; i < width; ++i)
863 /* Parse a timestamp field from a PostgreSQL database, and return it
864 * broken out into the dbi_timestamp structure. This can also parse
868 parse_timestamp (st_handle sth, const char *str, struct dbi_timestamp *ts)
871 const char *s, *sign;
873 /* Parse the timestamp. */
874 v = prematch (sth->pool, str, re_timestamp, 0);
877 pth_die (psprintf (sth->pool,
878 "dbi: parse_timestamp: invalid timestamp: %s",
881 if (vector_size (v) <= 1) return;
882 vector_get (v, 1, s);
883 if (s) ts->year = parse_fixed_width_int (s, 4);
885 if (vector_size (v) <= 2) return;
886 vector_get (v, 2, s);
887 if (s) ts->month = parse_fixed_width_int (s, 2);
889 if (vector_size (v) <= 3) return;
890 vector_get (v, 3, s);
891 if (s) ts->day = parse_fixed_width_int (s, 2);
893 if (vector_size (v) <= 4) return;
894 vector_get (v, 4, s);
895 if (s) ts->hour = parse_fixed_width_int (s, 2);
897 if (vector_size (v) <= 5) return;
898 vector_get (v, 5, s);
899 if (s) ts->min = parse_fixed_width_int (s, 2);
901 if (vector_size (v) <= 6) return;
902 vector_get (v, 6, s);
903 if (s) ts->sec = parse_fixed_width_int (s, 2);
905 if (vector_size (v) <= 7) return;
906 vector_get (v, 7, s);
907 if (s) sscanf (s, "%d", &ts->microsecs);
909 if (vector_size (v) <= 9) return;
910 vector_get (v, 8, sign);
911 vector_get (v, 9, s);
914 ts->utc_offset = parse_fixed_width_int (s, 2);
915 if (sign[0] == '-') ts->utc_offset = -ts->utc_offset;
919 /* Parse an interval field from a PostgreSQL database, and return it
920 * broken out into the dbi_interval structure.
923 parse_interval (st_handle sth, const char *str, struct dbi_interval *inv)
928 /* Parse the interval. */
929 v = prematch (sth->pool, str, re_interval, 0);
932 pth_die (psprintf (sth->pool,
933 "dbi: parse_interval: invalid interval: %s",
936 if (vector_size (v) <= 1) return;
937 vector_get (v, 1, s);
938 if (s) sscanf (s, "%d", &inv->years);
940 if (vector_size (v) <= 2) return;
941 vector_get (v, 2, s);
942 if (s) sscanf (s, "%d", &inv->months);
944 if (vector_size (v) <= 3) return;
945 vector_get (v, 3, s);
946 if (s) sscanf (s, "%d", &inv->days);
948 if (vector_size (v) <= 4) return;
949 vector_get (v, 4, s);
950 if (s) inv->hours = parse_fixed_width_int (s, 2);
952 if (vector_size (v) <= 5) return;
953 vector_get (v, 5, s);
954 if (s) inv->mins = parse_fixed_width_int (s, 2);
956 if (vector_size (v) <= 6) return;
957 vector_get (v, 6, s);
958 if (s) inv->secs = parse_fixed_width_int (s, 2);
962 st_fetch_all_rows (st_handle sth)
968 if (!sth->result || !sth->fetch_allowed)
971 "dbi: st_fetch_all_rows: fetch without execute, or on a non-SELECT statement";
973 fprintf (stderr, "%s\n", error);
974 if ((sth->dbh->flags & DBI_THROW_ERRORS))
980 DEBUG (sth->dbh, sth, "fetch_all_rows");
982 result = new_vector (sth->pool, vector);
984 /* Get number of rows, columns in the result. */
985 nr_rows = PQntuples (sth->result);
986 nr_cols = PQnfields (sth->result);
989 for (row = 0; row < nr_rows; ++row)
991 vector v = new_vector (sth->pool, char *);
993 for (col = 0; col < nr_cols; ++col)
995 char *s = PQgetisnull (sth->result, row, col)
996 ? 0 : PQgetvalue (sth->result, row, col);
998 vector_push_back (v, s);
1001 vector_push_back (result, v);
1008 st_finish (st_handle sth)
1011 PQclear (sth->result);
1014 DEBUG (sth->dbh, sth, "finished (explicit)");
1017 #ifndef HAVE_PQESCAPESTRING
1018 /* This is taken from the PostgreSQL source code. */
1021 * Escaping arbitrary strings to get valid SQL strings/identifiers.
1023 * Replaces "\\" with "\\\\" and "'" with "''".
1024 * length is the length of the buffer pointed to by
1025 * from. The buffer at to must be at least 2*length + 1 characters
1026 * long. A terminating NUL character is written.
1031 PQescapeString(char *to, const char *from, size_t length)
1033 const char *source = from;
1035 unsigned int remaining = length;
1037 while (remaining > 0)
1045 /* target and remaining are updated below. */
1052 /* target and remaining are updated below. */
1057 /* target and remaining are updated below. */
1064 /* Write the terminating NUL character. */
1073 * PQescapeBytea - converts from binary string to the
1074 * minimal encoding necessary to include the string in an SQL
1075 * INSERT statement with a bytea type column as the target.
1077 * The following transformations are applied
1078 * '\0' == ASCII 0 == \\000
1079 * '\'' == ASCII 39 == \'
1080 * '\\' == ASCII 92 == \\\\
1081 * anything >= 0x80 ---> \\ooo (where ooo is an octal expression)
1084 PQescapeBytea(unsigned char *bintext, size_t binlen, size_t *bytealen)
1088 unsigned char *result;
1093 * empty string has 1 char ('\0')
1098 for (i = binlen; i > 0; i--, vp++)
1100 if (*vp == 0 || *vp >= 0x80)
1101 len += 5; /* '5' is for '\\ooo' */
1102 else if (*vp == '\'')
1104 else if (*vp == '\\')
1110 rp = result = (unsigned char *) malloc(len);
1117 for (i = binlen; i > 0; i--, vp++)
1119 if (*vp == 0 || *vp >= 0x80)
1121 (void) sprintf(rp, "\\\\%03o", *vp);
1124 else if (*vp == '\'')
1130 else if (*vp == '\\')