1 /*
2  * This file Copyright (C) 2013-2014 Mnemosyne LLC
3  *
4  * It may be used under the GNU GPL versions 2 or 3
5  * or any future license endorsed by Mnemosyne LLC.
6  *
7  */
8 
9 #include <string.h> /* strlen() */
10 
11 #include "transmission.h"
12 #include "error.h"
13 #include "file.h"
14 #include "tr-assert.h"
15 #include "utils.h"
16 
tr_sys_file_read_line(tr_sys_file_t handle,char * buffer,size_t buffer_size,tr_error ** error)17 bool tr_sys_file_read_line(tr_sys_file_t handle, char* buffer, size_t buffer_size, tr_error** error)
18 {
19     TR_ASSERT(handle != TR_BAD_SYS_FILE);
20     TR_ASSERT(buffer != NULL);
21     TR_ASSERT(buffer_size > 0);
22 
23     bool ret = false;
24     size_t offset = 0;
25     uint64_t bytes_read;
26 
27     while (buffer_size > 0)
28     {
29         size_t const bytes_needed = MIN(buffer_size, 1024u);
30 
31         ret = tr_sys_file_read(handle, buffer + offset, bytes_needed, &bytes_read, error);
32 
33         if (!ret || (offset == 0 && bytes_read == 0))
34         {
35             ret = false;
36             break;
37         }
38 
39         TR_ASSERT(bytes_read <= bytes_needed);
40         TR_ASSERT(bytes_read <= buffer_size);
41 
42         int64_t delta = 0;
43 
44         for (size_t i = 0; i < bytes_read; ++i, ++offset, --buffer_size)
45         {
46             if (buffer[offset] == '\n')
47             {
48                 delta = i - (int64_t)bytes_read + 1;
49                 break;
50             }
51         }
52 
53         if (delta != 0 || buffer_size == 0 || bytes_read == 0)
54         {
55             if (delta != 0)
56             {
57                 ret = tr_sys_file_seek(handle, delta, TR_SEEK_CUR, NULL, error);
58 
59                 if (!ret)
60                 {
61                     break;
62                 }
63             }
64 
65             if (offset > 0 && buffer[offset - 1] == '\r')
66             {
67                 buffer[offset - 1] = '\0';
68             }
69             else
70             {
71                 buffer[offset] = '\0';
72             }
73 
74             break;
75         }
76     }
77 
78     return ret;
79 }
80 
tr_sys_file_write_line(tr_sys_file_t handle,char const * buffer,tr_error ** error)81 bool tr_sys_file_write_line(tr_sys_file_t handle, char const* buffer, tr_error** error)
82 {
83     TR_ASSERT(handle != TR_BAD_SYS_FILE);
84     TR_ASSERT(buffer != NULL);
85 
86     bool ret = tr_sys_file_write(handle, buffer, strlen(buffer), NULL, error);
87 
88     if (ret)
89     {
90         ret = tr_sys_file_write(handle, TR_NATIVE_EOL_STR, TR_NATIVE_EOL_STR_SIZE, NULL, error);
91     }
92 
93     return ret;
94 }
95 
tr_sys_file_write_fmt(tr_sys_file_t handle,char const * format,tr_error ** error,...)96 bool tr_sys_file_write_fmt(tr_sys_file_t handle, char const* format, tr_error** error, ...)
97 {
98     TR_ASSERT(handle != TR_BAD_SYS_FILE);
99     TR_ASSERT(format != NULL);
100 
101     bool ret = false;
102     char* buffer;
103     va_list args;
104 
105     va_start(args, error);
106     buffer = tr_strdup_vprintf(format, args);
107     va_end(args);
108 
109     if (buffer != NULL)
110     {
111         ret = tr_sys_file_write(handle, buffer, strlen(buffer), NULL, error);
112         tr_free(buffer);
113     }
114     else
115     {
116         tr_error_set_literal(error, 0, "Unable to format message.");
117     }
118 
119     return ret;
120 }
121