2
* cat.c: implementation of the 'cat' command
4
* ====================================================================
5
* Copyright (c) 2000-2004 CollabNet. All rights reserved.
7
* This software is licensed as described in the file COPYING, which
8
* you should have received as part of this distribution. The terms
9
* are also available at http://subversion.tigris.org/license-1.html.
10
* If newer versions of this license are posted there, you may use a
11
* newer version instead, at your option.
13
* This software consists of voluntary contributions made by many
14
* individuals. For exact contribution history, see the revision
15
* history and logs, available at http://subversion.tigris.org/.
16
* ====================================================================
19
/* ==================================================================== */
25
#include "svn_client.h"
26
#include "svn_string.h"
27
#include "svn_error.h"
28
#include "svn_subst.h"
32
#include "svn_props.h"
35
#include "svn_private_config.h"
40
/* Helper function to handle copying a potentially translated verison of BASE
41
or WORKING revision of a file to an output stream. */
43
cat_local_file (const char *path,
45
svn_wc_adm_access_t *adm_access,
46
const svn_opt_revision_t *revision,
49
const svn_wc_entry_t *entry;
50
svn_subst_keywords_t kw = { 0 };
51
svn_subst_eol_style_t style;
54
svn_string_t *eol_style, *keywords, *special;
55
const char *eol = NULL;
56
svn_boolean_t local_mod = FALSE;
58
apr_file_t *input_file;
61
SVN_ERR (svn_wc_entry (&entry, path, adm_access, FALSE, pool));
64
return svn_error_createf (SVN_ERR_UNVERSIONED_RESOURCE, NULL,
65
_("'%s' is not under version control "
67
svn_path_local_style (path, pool));
69
if (entry->kind != svn_node_file)
70
return svn_error_createf(SVN_ERR_CLIENT_IS_DIRECTORY, NULL,
71
_("'%s' refers to a directory"), path);
73
if (revision->kind != svn_opt_revision_working)
75
SVN_ERR (svn_wc_get_pristine_copy_path (path, &base, pool));
76
SVN_ERR (svn_wc_get_prop_diffs (NULL, &props, path, adm_access, pool));
80
svn_wc_status2_t *status;
83
SVN_ERR (svn_wc_prop_list (&props, path, adm_access, pool));
84
SVN_ERR (svn_wc_status2 (&status, path, adm_access, pool));
85
if (status->text_status != svn_wc_status_normal)
89
eol_style = apr_hash_get (props, SVN_PROP_EOL_STYLE,
91
keywords = apr_hash_get (props, SVN_PROP_KEYWORDS,
93
special = apr_hash_get (props, SVN_PROP_SPECIAL,
97
svn_subst_eol_style_from_value (&style, &eol, eol_style->data);
99
if (local_mod && (! special))
101
/* Use the modified time from the working copy if
103
SVN_ERR (svn_io_file_affected_time (&tm, path, pool));
107
tm = entry->cmt_date;
117
/* For locally modified files, we'll append an 'M'
118
to the revision number, and set the author to
119
"(local)" since we can't always determine the
120
current user's username */
122
author = _("(local)");
127
author = entry->cmt_author;
130
SVN_ERR (svn_subst_build_keywords
131
(&kw, keywords->data,
132
apr_psprintf (pool, fmt, entry->cmt_rev),
133
entry->url, tm, author, pool));
136
SVN_ERR (svn_io_file_open (&input_file, base,
137
APR_READ, APR_OS_DEFAULT, pool));
138
input = svn_stream_from_aprfile (input_file, pool);
140
SVN_ERR (svn_subst_translate_stream2 (input, output, eol, FALSE, &kw, TRUE,
143
SVN_ERR (svn_stream_close (input));
144
SVN_ERR (svn_io_file_close (input_file, pool));
150
svn_client_cat2 (svn_stream_t *out,
151
const char *path_or_url,
152
const svn_opt_revision_t *peg_revision,
153
const svn_opt_revision_t *revision,
154
svn_client_ctx_t *ctx,
157
svn_ra_session_t *ra_session;
159
svn_node_kind_t url_kind;
160
svn_string_t *eol_style;
161
svn_string_t *keywords;
165
if (! svn_path_is_url (path_or_url)
166
&& (peg_revision->kind == svn_opt_revision_base
167
|| peg_revision->kind == svn_opt_revision_committed
168
|| peg_revision->kind == svn_opt_revision_unspecified)
169
&& (revision->kind == svn_opt_revision_base
170
|| revision->kind == svn_opt_revision_committed
171
|| revision->kind == svn_opt_revision_unspecified))
173
svn_wc_adm_access_t *adm_access;
175
SVN_ERR (svn_wc_adm_open3 (&adm_access, NULL,
176
svn_path_dirname (path_or_url, pool), FALSE,
177
0, ctx->cancel_func, ctx->cancel_baton,
180
SVN_ERR (cat_local_file (path_or_url, out, adm_access, revision, pool));
182
SVN_ERR (svn_wc_adm_close (adm_access));
187
/* Get an RA plugin for this filesystem object. */
188
SVN_ERR (svn_client__ra_session_from_path (&ra_session, &rev,
189
&url, path_or_url, peg_revision,
190
revision, ctx, pool));
192
/* Make sure the object isn't a directory. */
193
SVN_ERR (svn_ra_check_path (ra_session, "", rev, &url_kind, pool));
194
if (url_kind == svn_node_dir)
195
return svn_error_createf(SVN_ERR_CLIENT_IS_DIRECTORY, NULL,
196
_("URL '%s' refers to a directory"), url);
198
/* Grab some properties we need to know in order to figure out if anything
199
special needs to be done with this file. */
200
SVN_ERR (svn_ra_get_file (ra_session, "", rev, NULL, NULL, &props, pool));
202
eol_style = apr_hash_get (props, SVN_PROP_EOL_STYLE, APR_HASH_KEY_STRING);
203
keywords = apr_hash_get (props, SVN_PROP_KEYWORDS, APR_HASH_KEY_STRING);
205
if (! eol_style && ! keywords)
207
/* It's a file with no special eol style or keywords. */
208
SVN_ERR (svn_ra_get_file (ra_session, "", rev, out, NULL, NULL, pool));
212
svn_subst_keywords_t kw = { 0 };
213
svn_subst_eol_style_t style;
214
const char *temp_dir;
215
const char *tmp_filename;
216
svn_stream_t *tmp_stream;
217
apr_file_t *tmp_file;
218
apr_status_t apr_err;
220
const char *eol = NULL;
222
/* grab a temporary file to write the target to. */
223
SVN_ERR (svn_io_temp_dir (&temp_dir, pool));
224
SVN_ERR (svn_io_open_unique_file (&tmp_file, &tmp_filename,
225
svn_path_join (temp_dir, "tmp", pool), ".tmp",
228
tmp_stream = svn_stream_from_aprfile (tmp_file, pool);
230
SVN_ERR (svn_ra_get_file (ra_session, "", rev, tmp_stream,
233
/* rewind our stream. */
234
apr_err = apr_file_seek (tmp_file, APR_SET, &off);
236
return svn_error_wrap_apr (apr_err, _("Can't seek in '%s'"),
237
svn_path_local_style (tmp_filename, pool));
240
svn_subst_eol_style_from_value (&style, &eol, eol_style->data);
244
svn_string_t *cmt_rev, *cmt_date, *cmt_author;
247
cmt_rev = apr_hash_get (props, SVN_PROP_ENTRY_COMMITTED_REV,
248
APR_HASH_KEY_STRING);
249
cmt_date = apr_hash_get (props, SVN_PROP_ENTRY_COMMITTED_DATE,
250
APR_HASH_KEY_STRING);
251
cmt_author = apr_hash_get (props, SVN_PROP_ENTRY_LAST_AUTHOR,
252
APR_HASH_KEY_STRING);
254
SVN_ERR (svn_time_from_cstring (&when, cmt_date->data, pool));
256
SVN_ERR (svn_subst_build_keywords
257
(&kw, keywords->data,
261
cmt_author ? cmt_author->data : NULL,
265
SVN_ERR (svn_subst_translate_stream2 (tmp_stream, out, eol, FALSE, &kw,
268
SVN_ERR (svn_stream_close (tmp_stream));
275
svn_client_cat (svn_stream_t *out,
276
const char *path_or_url,
277
const svn_opt_revision_t *revision,
278
svn_client_ctx_t *ctx,
281
return svn_client_cat2 (out, path_or_url, revision, revision,