~ubuntu-branches/debian/sid/subversion/sid

« back to all changes in this revision

Viewing changes to subversion/libsvn_subr/prompt.c

  • Committer: Package Import Robot
  • Author(s): James McCoy, Peter Samuelson, James McCoy
  • Date: 2014-01-12 19:48:33 UTC
  • mfrom: (0.2.10)
  • Revision ID: package-import@ubuntu.com-20140112194833-w3axfwksn296jn5x
Tags: 1.8.5-1
[ Peter Samuelson ]
* New upstream release.  (Closes: #725787) Rediff patches:
  - Remove apr-abi1 (applied upstream), rename apr-abi2 to apr-abi
  - Remove loosen-sqlite-version-check (shouldn't be needed)
  - Remove java-osgi-metadata (applied upstream)
  - svnmucc prompts for a changelog if none is provided. (Closes: #507430)
  - Remove fix-bdb-version-detection, upstream uses "apu-config --dbm-libs"
  - Remove ruby-test-wc (applied upstream)
  - Fix “svn diff -r N file” when file has svn:mime-type set.
    (Closes: #734163)
  - Support specifying an encoding for mod_dav_svn's environment in which
    hooks are run.  (Closes: #601544)
  - Fix ordering of “svnadmin dump” paths with certain APR versions.
    (Closes: #687291)
  - Provide a better error message when authentication fails with an
    svn+ssh:// URL.  (Closes: #273874)
  - Updated Polish translations.  (Closes: #690815)

[ James McCoy ]
* Remove all traces of libneon, replaced by libserf.
* patches/sqlite_3.8.x_workaround: Upstream fix for wc-queries-test test
  failurse.
* Run configure with --with-apache-libexecdir, which allows removing part of
  patches/rpath.
* Re-enable auth-test as upstream has fixed the problem of picking up
  libraries from the environment rather than the build tree.
  (Closes: #654172)
* Point LD_LIBRARY_PATH at the built auth libraries when running the svn
  command during the build.  (Closes: #678224)
* Add a NEWS entry describing how to configure mod_dav_svn to understand
  UTF-8.  (Closes: #566148)
* Remove ancient transitional package, libsvn-ruby.
* Enable compatibility with Sqlite3 versions back to Wheezy.
* Enable hardening flags.  (Closes: #734918)
* patches/build-fixes: Enable verbose build logs.
* Build against the default ruby version.  (Closes: #722393)

Show diffs side-by-side

added added

removed removed

Lines of Context:
29
29
 
30
30
#include <apr_lib.h>
31
31
#include <apr_poll.h>
 
32
#include <apr_portable.h>
32
33
 
33
34
#include "svn_cmdline.h"
 
35
#include "svn_ctype.h"
34
36
#include "svn_string.h"
35
37
#include "svn_auth.h"
36
38
#include "svn_error.h"
39
41
#include "private/svn_cmdline_private.h"
40
42
#include "svn_private_config.h"
41
43
 
 
44
#ifdef WIN32
 
45
#include <conio.h>
 
46
#elif defined(HAVE_TERMIOS_H)
 
47
#include <signal.h>
 
48
#include <termios.h>
 
49
#endif
 
50
 
42
51
 
43
52
 
44
 
/* Wait for input on @a *f.  Doing all allocations
45
 
 * in @a pool.  This functions is based on apr_wait_for_io_or_timeout().
46
 
 * Note that this will return an EINTR on a signal.
47
 
 *
48
 
 * ### FIX: When APR gives us a better way of doing this use it. */
49
 
static apr_status_t wait_for_input(apr_file_t *f,
50
 
                                   apr_pool_t *pool)
51
 
{
52
 
#ifndef WIN32
53
 
  apr_pollfd_t pollset;
54
 
  int srv, n;
55
 
 
56
 
  pollset.desc_type = APR_POLL_FILE;
57
 
  pollset.desc.f = f;
58
 
  pollset.p = pool;
59
 
  pollset.reqevents = APR_POLLIN;
60
 
 
61
 
  srv = apr_poll(&pollset, 1, &n, -1);
62
 
 
63
 
  if (n == 1 && pollset.rtnevents & APR_POLLIN)
64
 
    return APR_SUCCESS;
65
 
 
66
 
  return srv;
67
 
#else
68
 
  /* APR specs say things that are unimplemented are supposed to return
69
 
   * APR_ENOTIMPL.  But when trying to use APR_POLL_FILE with apr_poll
70
 
   * on Windows it returns APR_EBADF instead.  So just return APR_ENOTIMPL
71
 
   * ourselves here.
72
 
   */
73
 
  return APR_ENOTIMPL;
74
 
#endif
75
 
}
 
53
/* Descriptor of an open terminal */
 
54
typedef struct terminal_handle_t terminal_handle_t;
 
55
struct terminal_handle_t
 
56
{
 
57
  apr_file_t *infd;              /* input file handle */
 
58
  apr_file_t *outfd;             /* output file handle */
 
59
  svn_boolean_t noecho;          /* terminal echo was turned off */
 
60
  svn_boolean_t close_handles;   /* close handles when closing the terminal */
 
61
  apr_pool_t *pool;              /* pool associated with the file handles */
 
62
 
 
63
#ifdef HAVE_TERMIOS_H
 
64
  svn_boolean_t restore_state;   /* terminal state was changed */
 
65
  apr_os_file_t osinfd;          /* OS-specific handle for infd */
 
66
  struct termios attr;           /* saved terminal attributes */
 
67
#endif
 
68
};
 
69
 
 
70
/* Initialize safe state of terminal_handle_t. */
 
71
static void
 
72
terminal_handle_init(terminal_handle_t *terminal,
 
73
                     apr_file_t *infd, apr_file_t *outfd,
 
74
                     svn_boolean_t noecho, svn_boolean_t close_handles,
 
75
                     apr_pool_t *pool)
 
76
{
 
77
  memset(terminal, 0, sizeof(*terminal));
 
78
  terminal->infd = infd;
 
79
  terminal->outfd = outfd;
 
80
  terminal->noecho = noecho;
 
81
  terminal->close_handles = close_handles;
 
82
  terminal->pool = pool;
 
83
}
 
84
 
 
85
/*
 
86
 * Common pool cleanup handler for terminal_handle_t. Closes TERMINAL.
 
87
 * If CLOSE_HANDLES is TRUE, close the terminal file handles.
 
88
 * If RESTORE_STATE is TRUE, restores the TERMIOS flags of the terminal.
 
89
 */
 
90
static apr_status_t
 
91
terminal_cleanup_handler(terminal_handle_t *terminal,
 
92
                         svn_boolean_t close_handles,
 
93
                         svn_boolean_t restore_state)
 
94
{
 
95
  apr_status_t status = APR_SUCCESS;
 
96
 
 
97
#ifdef HAVE_TERMIOS_H
 
98
  /* Restore terminal state flags. */
 
99
  if (restore_state && terminal->restore_state)
 
100
    tcsetattr(terminal->osinfd, TCSANOW, &terminal->attr);
 
101
#endif
 
102
 
 
103
  /* Close terminal handles. */
 
104
  if (close_handles && terminal->close_handles)
 
105
    {
 
106
      apr_file_t *const infd = terminal->infd;
 
107
      apr_file_t *const outfd = terminal->outfd;
 
108
 
 
109
      if (infd)
 
110
        {
 
111
          terminal->infd = NULL;
 
112
          status = apr_file_close(infd);
 
113
        }
 
114
 
 
115
      if (!status && outfd && outfd != infd)
 
116
        {
 
117
          terminal->outfd = NULL;
 
118
          status = apr_file_close(terminal->outfd);
 
119
        }
 
120
    }
 
121
  return status;
 
122
}
 
123
 
 
124
/* Normal pool cleanup for a terminal. */
 
125
static apr_status_t terminal_plain_cleanup(void *baton)
 
126
{
 
127
  return terminal_cleanup_handler(baton, FALSE, TRUE);
 
128
}
 
129
 
 
130
/* Child pool cleanup for a terminal -- does not restore echo state. */
 
131
static apr_status_t terminal_child_cleanup(void *baton)
 
132
{
 
133
  return terminal_cleanup_handler(baton, FALSE, FALSE);
 
134
}
 
135
 
 
136
/* Explicitly close the terminal, removing its cleanup handlers. */
 
137
static svn_error_t *
 
138
terminal_close(terminal_handle_t *terminal)
 
139
{
 
140
  apr_status_t status;
 
141
 
 
142
  /* apr_pool_cleanup_kill() removes both normal and child cleanup */
 
143
  apr_pool_cleanup_kill(terminal->pool, terminal, terminal_plain_cleanup);
 
144
 
 
145
  status = terminal_cleanup_handler(terminal, TRUE, TRUE);
 
146
  if (status)
 
147
    return svn_error_create(status, NULL, _("Can't close terminal"));
 
148
  return SVN_NO_ERROR;
 
149
}
 
150
 
 
151
/* Allocate and open *TERMINAL. If NOECHO is TRUE, try to turn off
 
152
   terminal echo.  Use POOL for all allocations.*/
 
153
static svn_error_t *
 
154
terminal_open(terminal_handle_t **terminal, svn_boolean_t noecho,
 
155
              apr_pool_t *pool)
 
156
{
 
157
  apr_status_t status;
 
158
 
 
159
#ifdef WIN32
 
160
  /* On Windows, we'll use the console API directly if the process has
 
161
     a console attached; otherwise we'll just use stdin and stderr. */
 
162
  const HANDLE conin = CreateFileW(L"CONIN$", GENERIC_READ,
 
163
                                   FILE_SHARE_READ | FILE_SHARE_WRITE,
 
164
                                   NULL, OPEN_EXISTING,
 
165
                                   FILE_ATTRIBUTE_NORMAL, NULL);
 
166
  *terminal = apr_palloc(pool, sizeof(terminal_handle_t));
 
167
  if (conin != INVALID_HANDLE_VALUE)
 
168
    {
 
169
      /* The process has a console. */
 
170
      CloseHandle(conin);
 
171
      terminal_handle_init(*terminal, NULL, NULL, noecho, FALSE, NULL);
 
172
      return SVN_NO_ERROR;
 
173
    }
 
174
#else  /* !WIN32 */
 
175
  /* Without evidence to the contrary, we'll assume this is *nix and
 
176
     try to open /dev/tty. If that fails, we'll use stdin for input
 
177
     and stderr for prompting. */
 
178
  apr_file_t *tmpfd;
 
179
  status = apr_file_open(&tmpfd, "/dev/tty",
 
180
                         APR_FOPEN_READ | APR_FOPEN_WRITE,
 
181
                         APR_OS_DEFAULT, pool);
 
182
  *terminal = apr_palloc(pool, sizeof(terminal_handle_t));
 
183
  if (!status)
 
184
    {
 
185
      /* We have a terminal handle that we can use for input and output. */
 
186
      terminal_handle_init(*terminal, tmpfd, tmpfd, FALSE, TRUE, pool);
 
187
    }
 
188
#endif /* !WIN32 */
 
189
  else
 
190
    {
 
191
      /* There is no terminal. Sigh. */
 
192
      apr_file_t *infd;
 
193
      apr_file_t *outfd;
 
194
 
 
195
      status = apr_file_open_stdin(&infd, pool);
 
196
      if (status)
 
197
        return svn_error_wrap_apr(status, _("Can't open stdin"));
 
198
      status = apr_file_open_stderr(&outfd, pool);
 
199
      if (status)
 
200
        return svn_error_wrap_apr(status, _("Can't open stderr"));
 
201
      terminal_handle_init(*terminal, infd, outfd, FALSE, FALSE, pool);
 
202
    }
 
203
 
 
204
#ifdef HAVE_TERMIOS_H
 
205
  /* Set terminal state */
 
206
  if (0 == apr_os_file_get(&(*terminal)->osinfd, (*terminal)->infd))
 
207
    {
 
208
      if (0 == tcgetattr((*terminal)->osinfd, &(*terminal)->attr))
 
209
        {
 
210
          struct termios attr = (*terminal)->attr;
 
211
          /* Turn off signal handling and canonical input mode */
 
212
          attr.c_lflag &= ~(ISIG | ICANON);
 
213
          attr.c_cc[VMIN] = 1;          /* Read one byte at a time */
 
214
          attr.c_cc[VTIME] = 0;         /* No timeout, wait indefinitely */
 
215
          attr.c_lflag &= ~(ECHO);      /* Turn off echo */
 
216
          if (0 == tcsetattr((*terminal)->osinfd, TCSAFLUSH, &attr))
 
217
            {
 
218
              (*terminal)->noecho = noecho;
 
219
              (*terminal)->restore_state = TRUE;
 
220
            }
 
221
        }
 
222
    }
 
223
#endif /* HAVE_TERMIOS_H */
 
224
 
 
225
  /* Register pool cleanup to close handles and restore echo state. */
 
226
  apr_pool_cleanup_register((*terminal)->pool, *terminal,
 
227
                            terminal_plain_cleanup,
 
228
                            terminal_child_cleanup);
 
229
  return SVN_NO_ERROR;
 
230
}
 
231
 
 
232
/* Write a null-terminated STRING to TERMINAL.
 
233
   Use POOL for allocations related to converting STRING from UTF-8. */
 
234
static svn_error_t *
 
235
terminal_puts(const char *string, terminal_handle_t *terminal,
 
236
              apr_pool_t *pool)
 
237
{
 
238
  svn_error_t *err;
 
239
  apr_status_t status;
 
240
  const char *converted;
 
241
 
 
242
  err = svn_cmdline_cstring_from_utf8(&converted, string, pool);
 
243
  if (err)
 
244
    {
 
245
      svn_error_clear(err);
 
246
      converted = svn_cmdline_cstring_from_utf8_fuzzy(string, pool);
 
247
    }
 
248
 
 
249
#ifdef WIN32
 
250
  if (!terminal->outfd)
 
251
    {
 
252
      /* See terminal_open; we're using Console I/O. */
 
253
      _cputs(converted);
 
254
      return SVN_NO_ERROR;
 
255
    }
 
256
#endif
 
257
 
 
258
  status = apr_file_write_full(terminal->outfd, converted,
 
259
                               strlen(converted), NULL);
 
260
  if (!status)
 
261
    status = apr_file_flush(terminal->outfd);
 
262
  if (status)
 
263
    return svn_error_wrap_apr(status, _("Can't write to terminal"));
 
264
  return SVN_NO_ERROR;
 
265
}
 
266
 
 
267
/* These codes can be returned from terminal_getc instead of a character. */
 
268
#define TERMINAL_NONE  0x80000               /* no character read, retry */
 
269
#define TERMINAL_DEL   (TERMINAL_NONE + 1)   /* the input was a deleteion */
 
270
#define TERMINAL_EOL   (TERMINAL_NONE + 2)   /* end of input/end of line */
 
271
#define TERMINAL_EOF   (TERMINAL_NONE + 3)   /* end of file during input */
 
272
 
 
273
/* Helper for terminal_getc: writes CH to OUTFD as a control char. */
 
274
#ifndef WIN32
 
275
static void
 
276
echo_control_char(char ch, apr_file_t *outfd)
 
277
{
 
278
  if (svn_ctype_iscntrl(ch))
 
279
    {
 
280
      const char substitute = (ch < 32? '@' + ch : '?');
 
281
      apr_file_putc('^', outfd);
 
282
      apr_file_putc(substitute, outfd);
 
283
    }
 
284
  else if (svn_ctype_isprint(ch))
 
285
    {
 
286
      /* Pass printable characters unchanged. */
 
287
      apr_file_putc(ch, outfd);
 
288
    }
 
289
  else
 
290
    {
 
291
      /* Everything else is strange. */
 
292
      apr_file_putc('^', outfd);
 
293
      apr_file_putc('!', outfd);
 
294
    }
 
295
}
 
296
#endif /* WIN32 */
 
297
 
 
298
/* Read one character or control code from TERMINAL, returning it in CODE.
 
299
   if CAN_ERASE and the input was a deletion, emit codes to erase the
 
300
   last character displayed on the terminal.
 
301
   Use POOL for all allocations. */
 
302
static svn_error_t *
 
303
terminal_getc(int *code, terminal_handle_t *terminal,
 
304
              svn_boolean_t can_erase, apr_pool_t *pool)
 
305
{
 
306
  const svn_boolean_t echo = !terminal->noecho;
 
307
  apr_status_t status = APR_SUCCESS;
 
308
  char ch;
 
309
 
 
310
#ifdef WIN32
 
311
  if (!terminal->infd)
 
312
    {
 
313
      /* See terminal_open; we're using Console I/O. */
 
314
 
 
315
      /*  The following was hoisted from APR's getpass for Windows. */
 
316
      int concode = _getch();
 
317
      switch (concode)
 
318
        {
 
319
        case '\r':                      /* end-of-line */
 
320
          *code = TERMINAL_EOL;
 
321
          if (echo)
 
322
            _cputs("\r\n");
 
323
          break;
 
324
 
 
325
        case EOF:                       /* end-of-file */
 
326
        case 26:                        /* Ctrl+Z */
 
327
          *code = TERMINAL_EOF;
 
328
          if (echo)
 
329
            _cputs((concode == EOF ? "[EOF]\r\n" : "^Z\r\n"));
 
330
          break;
 
331
 
 
332
        case 3:                         /* Ctrl+C, Ctrl+Break */
 
333
          /* _getch() bypasses Ctrl+C but not Ctrl+Break detection! */
 
334
          if (echo)
 
335
            _cputs("^C\r\n");
 
336
          return svn_error_create(SVN_ERR_CANCELLED, NULL, NULL);
 
337
 
 
338
        case 0:                         /* Function code prefix */
 
339
        case 0xE0:
 
340
          concode = (concode << 4) | _getch();
 
341
          /* Catch {DELETE}, {<--}, Num{DEL} and Num{<--} */
 
342
          if (concode == 0xE53 || concode == 0xE4B
 
343
              || concode == 0x053 || concode == 0x04B)
 
344
            {
 
345
              *code = TERMINAL_DEL;
 
346
              if (can_erase)
 
347
                _cputs("\b \b");
 
348
            }
 
349
          else
 
350
            {
 
351
              *code = TERMINAL_NONE;
 
352
              _putch('\a');
 
353
            }
 
354
          break;
 
355
 
 
356
        case '\b':                      /* BS */
 
357
        case 127:                       /* DEL */
 
358
          *code = TERMINAL_DEL;
 
359
          if (can_erase)
 
360
            _cputs("\b \b");
 
361
          break;
 
362
 
 
363
        default:
 
364
          if (!apr_iscntrl(concode))
 
365
            {
 
366
              *code = (int)(unsigned char)concode;
 
367
              _putch(echo ? concode : '*');
 
368
            }
 
369
          else
 
370
            {
 
371
              *code = TERMINAL_NONE;
 
372
              _putch('\a');
 
373
            }
 
374
        }
 
375
      return SVN_NO_ERROR;
 
376
    }
 
377
#elif defined(HAVE_TERMIOS_H)
 
378
  if (terminal->restore_state)
 
379
    {
 
380
      /* We're using a bytewise-immediate termios input */
 
381
      const struct termios *const attr = &terminal->attr;
 
382
 
 
383
      status = apr_file_getc(&ch, terminal->infd);
 
384
      if (status)
 
385
        return svn_error_wrap_apr(status, _("Can't read from terminal"));
 
386
 
 
387
      if (ch == attr->c_cc[VINTR] || ch == attr->c_cc[VQUIT])
 
388
        {
 
389
          /* Break */
 
390
          echo_control_char(ch, terminal->outfd);
 
391
          return svn_error_create(SVN_ERR_CANCELLED, NULL, NULL);
 
392
        }
 
393
      else if (ch == '\r' || ch == '\n' || ch == attr->c_cc[VEOL])
 
394
        {
 
395
          /* Newline */
 
396
          *code = TERMINAL_EOL;
 
397
          apr_file_putc('\n', terminal->outfd);
 
398
        }
 
399
      else if (ch == '\b' || ch == attr->c_cc[VERASE])
 
400
        {
 
401
          /* Delete */
 
402
          *code = TERMINAL_DEL;
 
403
          if (can_erase)
 
404
            {
 
405
              apr_file_putc('\b', terminal->outfd);
 
406
              apr_file_putc(' ', terminal->outfd);
 
407
              apr_file_putc('\b', terminal->outfd);
 
408
            }
 
409
        }
 
410
      else if (ch == attr->c_cc[VEOF])
 
411
        {
 
412
          /* End of input */
 
413
          *code = TERMINAL_EOF;
 
414
          echo_control_char(ch, terminal->outfd);
 
415
        }
 
416
      else if (ch == attr->c_cc[VSUSP])
 
417
        {
 
418
          /* Suspend */
 
419
          *code = TERMINAL_NONE;
 
420
          kill(0, SIGTSTP);
 
421
        }
 
422
      else if (!apr_iscntrl(ch))
 
423
        {
 
424
          /* Normal character */
 
425
          *code = (int)(unsigned char)ch;
 
426
          apr_file_putc((echo ? ch : '*'), terminal->outfd);
 
427
        }
 
428
      else
 
429
        {
 
430
          /* Ignored character */
 
431
          *code = TERMINAL_NONE;
 
432
          apr_file_putc('\a', terminal->outfd);
 
433
        }
 
434
      return SVN_NO_ERROR;
 
435
    }
 
436
#endif /* HAVE_TERMIOS_H */
 
437
 
 
438
  /* Fall back to plain stream-based I/O. */
 
439
#ifndef WIN32
 
440
  /* Wait for input on termin. This code is based on
 
441
     apr_wait_for_io_or_timeout().
 
442
     Note that this will return an EINTR on a signal. */
 
443
  {
 
444
    apr_pollfd_t pollset;
 
445
    int n;
 
446
 
 
447
    pollset.desc_type = APR_POLL_FILE;
 
448
    pollset.desc.f = terminal->infd;
 
449
    pollset.p = pool;
 
450
    pollset.reqevents = APR_POLLIN;
 
451
 
 
452
    status = apr_poll(&pollset, 1, &n, -1);
 
453
 
 
454
    if (n == 1 && pollset.rtnevents & APR_POLLIN)
 
455
      status = APR_SUCCESS;
 
456
  }
 
457
#endif /* !WIN32 */
 
458
 
 
459
  if (!status)
 
460
    status = apr_file_getc(&ch, terminal->infd);
 
461
  if (APR_STATUS_IS_EINTR(status))
 
462
    {
 
463
      *code = TERMINAL_NONE;
 
464
      return SVN_NO_ERROR;
 
465
    }
 
466
  else if (APR_STATUS_IS_EOF(status))
 
467
    {
 
468
      *code = TERMINAL_EOF;
 
469
      return SVN_NO_ERROR;
 
470
    }
 
471
  else if (status)
 
472
    return svn_error_wrap_apr(status, _("Can't read from terminal"));
 
473
 
 
474
  *code = (int)(unsigned char)ch;
 
475
  return SVN_NO_ERROR;
 
476
}
 
477
 
76
478
 
77
479
/* Set @a *result to the result of prompting the user with @a
78
480
 * prompt_msg.  Use @ *pb to get the cancel_func and cancel_baton.
91
493
  /* XXX: If this functions ever starts using members of *pb
92
494
   * which were not included in svn_cmdline_prompt_baton_t,
93
495
   * we need to update svn_cmdline_prompt_user2 and its callers. */
94
 
  apr_status_t status;
95
 
  apr_file_t *fp;
 
496
 
 
497
  svn_boolean_t saw_first_half_of_eol = FALSE;
 
498
  svn_stringbuf_t *strbuf = svn_stringbuf_create_empty(pool);
 
499
  terminal_handle_t *terminal;
 
500
  int code;
96
501
  char c;
97
502
 
98
 
  svn_stringbuf_t *strbuf = svn_stringbuf_create("", pool);
99
 
 
100
 
  status = apr_file_open_stdin(&fp, pool);
101
 
  if (status)
102
 
    return svn_error_wrap_apr(status, _("Can't open stdin"));
103
 
 
104
 
  if (! hide)
105
 
    {
106
 
      svn_boolean_t saw_first_half_of_eol = FALSE;
107
 
      SVN_ERR(svn_cmdline_fputs(prompt_msg, stderr, pool));
108
 
      fflush(stderr);
109
 
 
110
 
      while (1)
111
 
        {
112
 
          /* Hack to allow us to not block for io on the prompt, so
113
 
           * we can cancel. */
114
 
          if (pb)
115
 
            SVN_ERR(pb->cancel_func(pb->cancel_baton));
116
 
          status = wait_for_input(fp, pool);
117
 
          if (APR_STATUS_IS_EINTR(status))
118
 
            continue;
119
 
          else if (status && status != APR_ENOTIMPL)
120
 
            return svn_error_wrap_apr(status, _("Can't read stdin"));
121
 
 
122
 
          status = apr_file_getc(&c, fp);
123
 
          if (status)
124
 
            return svn_error_wrap_apr(status, _("Can't read stdin"));
125
 
 
126
 
          if (saw_first_half_of_eol)
127
 
            {
128
 
              if (c == APR_EOL_STR[1])
129
 
                break;
130
 
              else
131
 
                saw_first_half_of_eol = FALSE;
132
 
            }
133
 
          else if (c == APR_EOL_STR[0])
134
 
            {
135
 
              /* GCC might complain here: "warning: will never be executed"
136
 
               * That's fine. This is a compile-time check for "\r\n\0" */
137
 
              if (sizeof(APR_EOL_STR) == 3)
138
 
                {
139
 
                  saw_first_half_of_eol = TRUE;
140
 
                  continue;
141
 
                }
142
 
              else if (sizeof(APR_EOL_STR) == 2)
143
 
                break;
144
 
              else
145
 
                /* ### APR_EOL_STR holds more than two chars?  Who
146
 
                   ever heard of such a thing? */
147
 
                SVN_ERR_MALFUNCTION();
148
 
            }
149
 
 
150
 
          svn_stringbuf_appendbyte(strbuf, c);
151
 
        }
152
 
    }
153
 
  else
154
 
    {
155
 
      const char *prompt_stdout;
156
 
      size_t bufsize = 300;
157
 
      SVN_ERR(svn_cmdline_cstring_from_utf8(&prompt_stdout, prompt_msg,
158
 
                                            pool));
159
 
      svn_stringbuf_ensure(strbuf, bufsize);
160
 
 
161
 
      status = apr_password_get(prompt_stdout, strbuf->data, &bufsize);
162
 
      if (status)
163
 
        return svn_error_wrap_apr(status, _("Can't get password"));
164
 
    }
 
503
  SVN_ERR(terminal_open(&terminal, hide, pool));
 
504
  SVN_ERR(terminal_puts(prompt_msg, terminal, pool));
 
505
 
 
506
  while (1)
 
507
    {
 
508
      SVN_ERR(terminal_getc(&code, terminal, (strbuf->len > 0), pool));
 
509
 
 
510
      /* Check for cancellation after a character has been read, some
 
511
         input processing modes may eat ^C and we'll only notice a
 
512
         cancellation signal after characters have been read --
 
513
         sometimes even after a newline. */
 
514
      if (pb)
 
515
        SVN_ERR(pb->cancel_func(pb->cancel_baton));
 
516
 
 
517
      switch (code)
 
518
        {
 
519
        case TERMINAL_NONE:
 
520
          /* Nothing useful happened; retry. */
 
521
          continue;
 
522
 
 
523
        case TERMINAL_DEL:
 
524
          /* Delete the last input character. terminal_getc takes care
 
525
             of erasing the feedback from the terminal, if applicable. */
 
526
          svn_stringbuf_chop(strbuf, 1);
 
527
          continue;
 
528
 
 
529
        case TERMINAL_EOL:
 
530
          /* End-of-line means end of input. Trick the EOL-detection code
 
531
             below to stop reading. */
 
532
          saw_first_half_of_eol = TRUE;
 
533
          c = APR_EOL_STR[1];   /* Could be \0 but still stops reading. */
 
534
          break;
 
535
 
 
536
        case TERMINAL_EOF:
 
537
          return svn_error_create(
 
538
              APR_EOF,
 
539
              terminal_close(terminal),
 
540
              _("End of file while reading from terminal"));
 
541
 
 
542
        default:
 
543
          /* Convert the returned code back to the character. */
 
544
          c = (char)code;
 
545
        }
 
546
 
 
547
      if (saw_first_half_of_eol)
 
548
        {
 
549
          if (c == APR_EOL_STR[1])
 
550
            break;
 
551
          else
 
552
            saw_first_half_of_eol = FALSE;
 
553
        }
 
554
      else if (c == APR_EOL_STR[0])
 
555
        {
 
556
          /* GCC might complain here: "warning: will never be executed"
 
557
           * That's fine. This is a compile-time check for "\r\n\0" */
 
558
          if (sizeof(APR_EOL_STR) == 3)
 
559
            {
 
560
              saw_first_half_of_eol = TRUE;
 
561
              continue;
 
562
            }
 
563
          else if (sizeof(APR_EOL_STR) == 2)
 
564
            break;
 
565
          else
 
566
            /* ### APR_EOL_STR holds more than two chars?  Who
 
567
               ever heard of such a thing? */
 
568
            SVN_ERR_MALFUNCTION();
 
569
        }
 
570
 
 
571
      svn_stringbuf_appendbyte(strbuf, c);
 
572
    }
 
573
 
 
574
  if (terminal->noecho)
 
575
    {
 
576
      /* If terminal echo was turned off, make sure future output
 
577
         to the terminal starts on a new line, as expected. */
 
578
      SVN_ERR(terminal_puts(APR_EOL_STR, terminal, pool));
 
579
    }
 
580
  SVN_ERR(terminal_close(terminal));
165
581
 
166
582
  return svn_cmdline_cstring_to_utf8(result, strbuf->data, pool);
167
583
}
179
595
{
180
596
  if (realm)
181
597
    {
182
 
      SVN_ERR(svn_cmdline_fprintf(stderr, pool,
183
 
                                  _("Authentication realm: %s\n"), realm));
184
 
      fflush(stderr);
 
598
      terminal_handle_t *terminal;
 
599
      SVN_ERR(terminal_open(&terminal, FALSE, pool));
 
600
      SVN_ERR(terminal_puts(
 
601
                  apr_psprintf(pool,
 
602
                               _("Authentication realm: %s\n"), realm),
 
603
                  terminal, pool));
 
604
      SVN_ERR(terminal_close(terminal));
185
605
    }
186
606
 
187
607
  return SVN_NO_ERROR;
396
816
  svn_boolean_t answered = FALSE;
397
817
  svn_cmdline_prompt_baton2_t *pb = baton;
398
818
  const char *config_path = NULL;
 
819
  terminal_handle_t *terminal;
399
820
 
400
821
  if (pb)
401
822
    SVN_ERR(svn_config_get_user_config_path(&config_path, pb->config_dir,
402
823
                                            SVN_CONFIG_CATEGORY_SERVERS, pool));
403
824
 
404
 
  SVN_ERR(svn_cmdline_fprintf(stderr, pool, prompt_text, realmstring,
405
 
                              config_path));
 
825
  SVN_ERR(terminal_open(&terminal, FALSE, pool));
 
826
  SVN_ERR(terminal_puts(apr_psprintf(pool, prompt_text,
 
827
                                     realmstring, config_path),
 
828
                        terminal, pool));
 
829
  SVN_ERR(terminal_close(terminal));
406
830
 
407
831
  do
408
832
    {