1 /**
2 * Copyright (C) 2014 Aaron Ball <nullspoon@iohq.net>
3 *
4 * Noteless is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * Noteless 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
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with noteless. If not, see <http://www.gnu.org/licenses/>.
16 */
17 #include "note.h"
18
19 /**
20 * Creates a new empty note object since no filename was specified.
21 */
22 note::note( path p ) {
23 _path = p;
24 name = _path.filename;
25 extension = get_extension();
26 }
27
28 /**
29 * Creates a new empty note object since no filename was specified.
30 */
31 note::note( string p ) {
32 path tmp_path( p );
33 _path = tmp_path;
34 name = _path.filename;
35 extension = get_extension();
36 }
37
38 /**
39 * Creates a new empty note object since no filename was specified.
40 */
41 note::note( string base, string note_name ) {
42 path tmp_path( base + "/" + note_name );
43 _path = tmp_path;
44 name = note_name;
45 extension = get_extension();
46 }
47
48 /**
49 * Opens a new note using the specified editor.
50 *
51 * @param string editor Path to the editor binary to use for editing.
52 *
53 * @return int Success or failure of the command
54 */
55 int note::create( string editor ) {
56 return edit( editor );
57 }
58
59 /**
60 * Opens a note using the specified editor
61 *
62 * @param string editor Path to the editor binary to use for editing.
63 *
64 * @return int Success or failure of the command
65 */
66 int note::edit( string editor ) {
67 string cmd = editor;
68 cmd += " ";
69 cmd += _path.out();
70 return system( cmd.c_str() );
71 }
72
73 /**
74 * Converts a 1 digit integer to a single char equivelant
75 *
76 * @param int i The integer to be converted
77 *
78 * @return char The char equivelent of the int argument
79 */
80 const char note::itoc( int i ) {
81 if( i == 0 ) {
82 return '0';
83 } else if( i == 1 ) {
84 return '1';
85 } else if( i == 2 ) {
86 return '2';
87 } else if( i == 3 ) {
88 return '3';
89 } else if( i == 4 ) {
90 return '4';
91 } else if( i == 5 ) {
92 return '5';
93 } else if( i == 6 ) {
94 return '6';
95 } else if( i == 7 ) {
96 return '7';
97 } else if( i == 8 ) {
98 return '8';
99 } else if( i == 9 ) {
100 return '9';
101 }
102 }
103
104 /**
105 * Converts an integer into a string
106 *
107 * @param int i - Integer to be converted
108 *
109 * @return string String equivelent of integer argument
110 */
111 string note::itos( int i ) {
112 string str = "";
113 // Since we don't want any black holes, return 0 without trying to divide by
114 // 10.
115 if( i == 0 ) {
116 return "0";
117 }
118 while( i != 0 ) {
119 str = itoc( i % 10 ) + str;
120 i /= 10;
121 }
122 return str;
123 }
124
125 /**
126 * Reads in the contents of the note. This exists so we don't have to keep
127 * writing the file open, check, get line, blah blah blah repeatedly.
128 *
129 * @return void
130 */
131 void note::read() {
132 // Don't do this unless body hasn't already been read
133 if( body.size() == 0 ) {
134 // Open the file
135 ifstream fs( _path.out().c_str() );
136
137 // Verify the file handle opened sucessfully
138 if( ! fs.is_open() ) {
139 cout << "Could not open file at " << _path.out() << "." << endl;
140 exit( 1 );
141 }
142
143 string line;
144 while( getline( fs, line ) ) {
145 body.push_back( line );
146 }
147 fs.close();
148 }
149 }
150
151 /**
152 * Returns the current localtime. Useful for "random" non-conflicting
153 * filenames.
154 *
155 * @return string The current date time in format YYYYMMDD.HHMMSS.
156 */
157 string note::get_current_date_time() {
158 string date;
159 time_t rawtime;
160 time( &rawtime );
161 struct tm* now = localtime( &rawtime );
162
163 // Date
164 // Year
165 int year = now->tm_year + 1900;
166 date += itos( year );
167 // Month
168 int mon = now->tm_mon + 1;
169 if( mon < 10 ) { date += "0"; }
170 date += itos( mon );
171 // Day
172 int day = now->tm_mday;
173 if( day < 10 ) { date += "0"; }
174 date += itos( day );
175
176 date += ".";
177
178 // Time
179 // Hour
180 int hour = now->tm_hour;
181 if( hour < 10 ) { date += "0"; }
182 date += itos( hour );
183 // Minute
184 int min = now->tm_min;
185 if( min < 10 ) { date += "0"; }
186 date += itos( min );
187 // Second
188 int sec = now->tm_sec;
189 if( sec < 10 ) { date += "0"; }
190 date += itos( sec );
191
192 return date;
193 }
194
195 /**
196 * Parses the current instance filename to determine its extension.
197 *
198 * @return string The filename. Null pointer if file has no extension.
199 */
200 string note::get_extension() {
201 string ext;
202 // Iterrate from the right to the left. This will keep us from catching
203 // filenames with multiple periods in them.
204 for( int i = name.length(); i > 0; i-- ) {
205 // Determine the index
206 if( name[i] == '.' ) {
207 // Increment so we don't get the period
208 i++;
209 ext = name.substr( i, name.length() - i );
210 break;
211 }
212 }
213 return ext;
214 }
215
216 /**
217 * Gets the filename of the current note instance without its extension.
218 *
219 * @return string Note filename without extension
220 */
221 string note::friendly_name() {
222 return name.substr( 0, name.length() - extension.length() - 1 );
223 }
224
225 /**
226 * TODO
227 */
228 vector<string> note::find( bool case_sensitive, string term ) {
229 vector<string> lines;
230
231 // Memory for storing matched lines
232 vector<string> matches;
233
234 // Read the notes contents into memory
235 read();
236
237 for( int i = 0; i < body.size(); i++ ) {
238 if( line_matches( body[i], term ) == true ) {
239 // Format the output
240 string out = friendly_name() + ": " + itos( i );
241 out += ": " + body[i];
242 // Add to the match list
243 matches.push_back( out );
244 }
245 }
246 return matches;
247 }
248
249 /**
250 * Performs a char by char comparison of a line and a search term. If the
251 * search term is found anywhere within the line even once, returns true;
252 * Otherwise, returns false.
253 *
254 * @param string line The line of text to search
255 * @param string term The search term
256 *
257 * @return bool Whether or not the search term was found in the line
258 */
259 bool note::line_matches( string line, string term ) {
260 // Define the two long arrays
261 long line_l[line.size()];
262 long term_l[term.size()];
263
264 // Convert the line to a long array
265 for( int i = 0; i < line.size(); i++ ) { line_l[i] = line[i]; }
266
267 // Convert the search term to a long array
268 for( int i = 0; i < term.size(); i++ ) { term_l[i] = term[i]; }
269
270
271 // Iterrate through each letter in the line
272 for( int l = 0; l < line.size(); l++ ) {
273 // Iterrate through the search term
274 for( int t = 0; t < term.size(); t++ ) {
275 if( term_l[t] >= 97 && term_l[t] <= 122 ) {
276 // Term char is lower. Compare down then up
277 if( line_l[l] != term_l[t]
278 && line_l[l] != term_l[t] - 32 ) {
279 break;
280 }
281 } else if( term_l[t] >= 65 && term_l[t] <= 90 ) {
282 // Term char is upper. Compare up then down
283 if( line_l[l] != term_l[t]
284 && line_l[l] != term_l[t] + 32 ) {
285 break;
286 }
287 } else {
288 // Term char isn't a letter. Must be a symbol or something ELSE...
289 // Teehee
290 if( line_l[l] != term_l[t] ) { break; }
291 }
292
293 // Increment the line letter to check the next one on the next search
294 // term letter loop
295 l++;
296 // If we reach the end of the search term, match!
297 if( t == term.size() - 1 ) { return true; }
298 }
299 }
300 return false;
301 }
|