1 //
2 // aegis - project change supervisor
3 // Copyright (C) 2006-2008, 2010, 2012 Peter Miller
4 //
5 // This program is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation; either version 3 of the License, or (at
8 // your option) any later version.
9 //
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 // General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with this program. If not, see <http://www.gnu.org/licenses/>.
17 //
18 
19 #include <common/ac/assert.h>
20 #include <common/ac/ctype.h>
21 #include <common/ac/string.h>
22 
23 #include <libaegis/attribute.h>
24 #include <libaegis/change/file.h>
25 #include <libaegis/fstate.fmtgen.h>
26 #include <libaegis/input/file.h>
27 #include <libaegis/os.h>
28 #include <libaegis/sub.h>
29 
30 #include <aede-policy/validation/files/printable.h>
31 
32 
~validation_files_printable()33 validation_files_printable::~validation_files_printable()
34 {
35 }
36 
37 
validation_files_printable()38 validation_files_printable::validation_files_printable()
39 {
40 }
41 
42 
43 validation::pointer
create(void)44 validation_files_printable::create(void)
45 {
46     return pointer(new validation_files_printable());
47 }
48 
49 
50 bool
check_binaries() const51 validation_files_printable::check_binaries()
52     const
53 {
54     return false;
55 }
56 
57 
58 static bool
international_character_set(fstate_src_ty * src)59 international_character_set(fstate_src_ty *src)
60 {
61     //
62     // If the content-type attribute doesn't exist, or no character set
63     // is specified by the content-type, plain ascii is assumed.
64     //
65     attributes_ty *ap = attributes_list_find(src->attribute, "content-type");
66     if (!ap || !ap->value)
67         return false;
68     const char *cp = strstr(ap->value->str_text, "charset=");
69     if (!cp)
70         return false;
71     cp += 8;
72     return (0 != strcmp(cp, "ascii") && 0 != strcmp(cp, "us-ascii"));
73 }
74 
75 
76 bool
check(change::pointer cp,fstate_src_ty * src)77 validation_files_printable::check(change::pointer cp, fstate_src_ty *src)
78 {
79     //
80     // Note: we return true if the file is acceptable to the policy
81     // (i.e. has no unprintable characters).  We return false if the
82     // file is unacceptable.
83     //
84     nstring path(cp->file_path(src));
85     assert(!path.empty());
86     if (path.empty())
87         return true;
88 
89     os_become_orig();
90     bool result = true;
91     input ip = input_file_open(path);
92     if
93     (
94         nstring(src->file_name).ends_with(".po")
95     ||
96         international_character_set(src)
97     )
98     {
99         //
100         // An obvious exception is the message translation files, which
101         // are supposed to contain character sets other than ASCII.
102         //
103         for (;;)
104         {
105             int c = ip->getch();
106             if (c < 0)
107                 break;
108             if (c == 0)
109             {
110                 sub_context_ty sc;
111                 sc.var_set_string("File_Name", src->file_name);
112                 change_error(cp, &sc, i18n("$filename: is binary"));
113                 result = false;
114                 break;
115             }
116         }
117     }
118     else
119     {
120         int line_number = 1;
121         for (;;)
122         {
123             int c = ip->getch();
124             if (c < 0)
125                 break;
126             if (c == 0)
127             {
128                 sub_context_ty sc;
129                 sc.var_set_string("File_Name", src->file_name);
130                 change_error(cp, &sc, i18n("$filename: is binary"));
131                 result = false;
132                 break;
133             }
134             unsigned char uc = c;
135             // Using the "C" locale.
136             if (!isprint(uc) && !isspace(uc))
137             {
138                 sub_context_ty sc;
139                 sc.var_set_string("File_Name", src->file_name);
140                 sc.var_set_long("Number", line_number);
141                 sc.var_optional("Number");
142                 change_error(cp, &sc, i18n("$filename: is unprintable"));
143                 result = false;
144                 break;
145             }
146             if (c == '\n')
147                 ++line_number;
148         }
149     }
150     ip.close();
151     os_become_undo();
152     return result;
153 }
154 
155 
156 // vim: set ts=8 sw=4 et :
157