1 /* ide-triplet.c
2  *
3  * Copyright 2018 Corentin Noël <corentin.noel@collabora.com>
4  * Copyright 2018 Collabora Ltd.
5  *
6  * This program is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
18  *
19  * SPDX-License-Identifier: GPL-3.0-or-later
20  */
21 
22 #define G_LOG_DOMAIN "ide-triplet"
23 
24 #include "config.h"
25 
26 #include "ide-triplet.h"
27 
28 G_DEFINE_BOXED_TYPE (IdeTriplet, ide_triplet, ide_triplet_ref, ide_triplet_unref)
29 
30 struct _IdeTriplet
31 {
32   volatile gint ref_count;
33 
34   gchar *full_name;
35   gchar *arch;
36   gchar *vendor;
37   gchar *kernel;
38   gchar *operating_system;
39 };
40 
41 static IdeTriplet *
_ide_triplet_construct(void)42 _ide_triplet_construct (void)
43 {
44   IdeTriplet *self;
45 
46   self = g_slice_new0 (IdeTriplet);
47   self->ref_count = 1;
48   self->full_name = NULL;
49   self->arch = NULL;
50   self->vendor = NULL;
51   self->kernel = NULL;
52   self->operating_system = NULL;
53 
54   return self;
55 }
56 
57 /**
58  * ide_triplet_new:
59  * @full_name: The complete identifier of the machine
60  *
61  * Creates a new #IdeTriplet from a given identifier. This identifier
62  * can be a simple architecture name, a duet of "arch-kernel" (like "m68k-coff"), a triplet
63  * of "arch-kernel-os" (like "x86_64-linux-gnu") or a quadriplet of "arch-vendor-kernel-os"
64  * (like "i686-pc-linux-gnu")
65  *
66  * Returns: (transfer full): An #IdeTriplet.
67  *
68  * Since: 3.32
69  */
70 IdeTriplet *
ide_triplet_new(const gchar * full_name)71 ide_triplet_new (const gchar *full_name)
72 {
73   IdeTriplet *self;
74   g_auto (GStrv) parts = NULL;
75   guint parts_length = 0;
76 
77   g_return_val_if_fail (full_name != NULL, NULL);
78 
79   self = _ide_triplet_construct ();
80   self->full_name = g_strdup (full_name);
81 
82   parts = g_strsplit (full_name, "-", 4);
83   parts_length = g_strv_length (parts);
84   /* Currently they can't have more than 4 parts */
85   if (parts_length >= 4)
86     {
87       self->arch = g_strdup (parts[0]);
88       self->vendor = g_strdup (parts[1]);
89       self->kernel = g_strdup (parts[2]);
90       self->operating_system = g_strdup (parts[3]);
91     }
92   else if (parts_length == 3)
93     {
94       self->arch = g_strdup (parts[0]);
95       self->kernel = g_strdup (parts[1]);
96       self->operating_system = g_strdup (parts[2]);
97     }
98   else if (parts_length == 2)
99     {
100       self->arch = g_strdup (parts[0]);
101       self->kernel = g_strdup (parts[1]);
102     }
103   else if (parts_length == 1)
104     self->arch = g_strdup (parts[0]);
105 
106   return self;
107 }
108 
109 /**
110  * ide_triplet_new_from_system:
111  *
112  * Creates a new #IdeTriplet from a the current system information
113  *
114  * Returns: (transfer full): An #IdeTriplet.
115  *
116  * Since: 3.32
117  */
118 IdeTriplet *
ide_triplet_new_from_system(void)119 ide_triplet_new_from_system (void)
120 {
121   static IdeTriplet *system_triplet;
122 
123   if (g_once_init_enter (&system_triplet))
124     g_once_init_leave (&system_triplet, ide_triplet_new (ide_get_system_type ()));
125 
126   return ide_triplet_ref (system_triplet);
127 }
128 
129 /**
130  * ide_triplet_new_with_triplet:
131  * @arch: The name of the architecture of the machine (like "x86_64")
132  * @kernel: (nullable): The name of the kernel of the machine (like "linux")
133  * @operating_system: (nullable): The name of the os of the machine
134  * (like "gnuabi64")
135  *
136  * Creates a new #IdeTriplet from a given triplet of "arch-kernel-os"
137  * (like "x86_64-linux-gnu")
138  *
139  * Returns: (transfer full): An #IdeTriplet.
140  *
141  * Since: 3.32
142  */
143 IdeTriplet *
ide_triplet_new_with_triplet(const gchar * arch,const gchar * kernel,const gchar * operating_system)144 ide_triplet_new_with_triplet (const gchar *arch,
145                               const gchar *kernel,
146                               const gchar *operating_system)
147 {
148   IdeTriplet *self;
149   g_autofree gchar *full_name = NULL;
150 
151   g_return_val_if_fail (arch != NULL, NULL);
152 
153   self = _ide_triplet_construct ();
154   self->arch = g_strdup (arch);
155   self->kernel = g_strdup (kernel);
156   self->operating_system = g_strdup (operating_system);
157 
158   full_name = g_strdup (arch);
159   if (kernel != NULL)
160     {
161       g_autofree gchar *start_full_name = full_name;
162       full_name = g_strdup_printf ("%s-%s", start_full_name, kernel);
163     }
164 
165   if (operating_system != NULL)
166     {
167       g_autofree gchar *start_full_name = full_name;
168       full_name = g_strdup_printf ("%s-%s", start_full_name, operating_system);
169     }
170 
171   self->full_name = g_steal_pointer (&full_name);
172 
173   return self;
174 }
175 
176 /**
177  * ide_triplet_new_with_quadruplet:
178  * @arch: The name of the architecture of the machine (like "x86_64")
179  * @vendor: (nullable): The name of the vendor of the machine (like "pc")
180  * @kernel: (nullable): The name of the kernel of the machine (like "linux")
181  * @operating_system: (nullable): The name of the os of the machine (like "gnuabi64")
182  *
183  * Creates a new #IdeTriplet from a given quadruplet of
184  * "arch-vendor-kernel-os" (like "i686-pc-linux-gnu")
185  *
186  * Returns: (transfer full): An #IdeTriplet.
187  *
188  * Since: 3.32
189  */
190 IdeTriplet *
ide_triplet_new_with_quadruplet(const gchar * arch,const gchar * vendor,const gchar * kernel,const gchar * operating_system)191 ide_triplet_new_with_quadruplet (const gchar *arch,
192                                  const gchar *vendor,
193                                  const gchar *kernel,
194                                  const gchar *operating_system)
195 {
196   IdeTriplet *self;
197   g_autofree gchar *full_name = NULL;
198 
199   g_return_val_if_fail (arch != NULL, NULL);
200 
201   if (vendor == NULL)
202     return ide_triplet_new_with_triplet (arch, kernel, operating_system);
203 
204   self = _ide_triplet_construct ();
205   self->arch = g_strdup (arch);
206   self->vendor = g_strdup (vendor);
207   self->kernel = g_strdup (kernel);
208   self->operating_system = g_strdup (operating_system);
209 
210   full_name = g_strdup_printf ("%s-%s", arch, vendor);
211   if (kernel != NULL)
212     {
213       g_autofree gchar *start_full_name = full_name;
214       full_name = g_strdup_printf ("%s-%s", start_full_name, kernel);
215     }
216 
217   if (operating_system != NULL)
218     {
219       g_autofree gchar *start_full_name = full_name;
220       full_name = g_strdup_printf ("%s-%s", start_full_name, operating_system);
221     }
222 
223   self->full_name = g_steal_pointer (&full_name);
224 
225   return self;
226 }
227 
228 static void
ide_triplet_finalize(IdeTriplet * self)229 ide_triplet_finalize (IdeTriplet *self)
230 {
231   g_free (self->full_name);
232   g_free (self->arch);
233   g_free (self->vendor);
234   g_free (self->kernel);
235   g_free (self->operating_system);
236   g_slice_free (IdeTriplet, self);
237 }
238 
239 /**
240  * ide_triplet_ref:
241  * @self: An #IdeTriplet
242  *
243  * Increases the reference count of @self
244  *
245  * Returns: (transfer none): An #IdeTriplet.
246  *
247  * Since: 3.32
248  */
249 IdeTriplet *
ide_triplet_ref(IdeTriplet * self)250 ide_triplet_ref (IdeTriplet *self)
251 {
252   g_return_val_if_fail (self, NULL);
253   g_return_val_if_fail (self->ref_count > 0, NULL);
254 
255   g_atomic_int_inc (&self->ref_count);
256 
257   return self;
258 }
259 
260 /**
261  * ide_triplet_unref:
262  * @self: An #IdeTriplet
263  *
264  * Decreases the reference count of @self
265  * Once the reference count reaches 0, the object is freed.
266  *
267  * Since: 3.32
268  */
269 void
ide_triplet_unref(IdeTriplet * self)270 ide_triplet_unref (IdeTriplet *self)
271 {
272   g_return_if_fail (self);
273   g_return_if_fail (self->ref_count > 0);
274 
275   if (g_atomic_int_dec_and_test (&self->ref_count))
276     ide_triplet_finalize (self);
277 }
278 
279 /**
280  * ide_triplet_get_full_name:
281  * @self: An #IdeTriplet
282  *
283  * Gets the full name of the machine configuration name (can be an architecture name,
284  * a duet, a triplet or a quadruplet).
285  *
286  * Returns: (transfer none): The full name of the machine configuration name
287  *
288  * Since: 3.32
289  */
290 const gchar *
ide_triplet_get_full_name(IdeTriplet * self)291 ide_triplet_get_full_name (IdeTriplet *self)
292 {
293   g_return_val_if_fail (self, NULL);
294 
295   return self->full_name;
296 }
297 
298 /**
299  * ide_triplet_get_arch:
300  * @self: An #IdeTriplet
301  *
302  * Gets the architecture name of the machine
303  *
304  * Returns: (transfer none): The architecture name of the machine
305  *
306  * Since: 3.32
307  */
308 const gchar *
ide_triplet_get_arch(IdeTriplet * self)309 ide_triplet_get_arch (IdeTriplet *self)
310 {
311   g_return_val_if_fail (self, NULL);
312 
313   return self->arch;
314 }
315 
316 /**
317  * ide_triplet_get_vendor:
318  * @self: An #IdeTriplet
319  *
320  * Gets the vendor name of the machine
321  *
322  * Returns: (transfer none) (nullable): The vendor name of the machine
323  *
324  * Since: 3.32
325  */
326 const gchar *
ide_triplet_get_vendor(IdeTriplet * self)327 ide_triplet_get_vendor (IdeTriplet *self)
328 {
329   g_return_val_if_fail (self, NULL);
330 
331   return self->vendor;
332 }
333 
334 /**
335  * ide_triplet_get_kernel:
336  * @self: An #IdeTriplet
337  *
338  * Gets name of the kernel of the machine
339  *
340  * Returns: (transfer none) (nullable): The name of the kernel of the machine
341  *
342  * Since: 3.32
343  */
344 const gchar *
ide_triplet_get_kernel(IdeTriplet * self)345 ide_triplet_get_kernel (IdeTriplet *self)
346 {
347   g_return_val_if_fail (self, NULL);
348 
349   return self->kernel;
350 }
351 
352 /**
353  * ide_triplet_get_operating_system:
354  * @self: An #IdeTriplet
355  *
356  * Gets name of the operating system of the machine
357  *
358  * Returns: (transfer none) (nullable): The name of the operating system of the machine
359  *
360  * Since: 3.32
361  */
362 const gchar *
ide_triplet_get_operating_system(IdeTriplet * self)363 ide_triplet_get_operating_system (IdeTriplet *self)
364 {
365   g_return_val_if_fail (self, NULL);
366 
367   return self->operating_system;
368 }
369 
370 
371 /**
372  * ide_triplet_is_system:
373  * @self: An #IdeTriplet
374  *
375  * Gets whether this is the same architecture as the system
376  *
377  * Returns: %TRUE if this is the same architecture as the system, %FALSE otherwise
378  *
379  * Since: 3.32
380  */
381 gboolean
ide_triplet_is_system(IdeTriplet * self)382 ide_triplet_is_system (IdeTriplet *self)
383 {
384   g_autofree gchar *system_arch = ide_get_system_arch ();
385 
386   g_return_val_if_fail (self, FALSE);
387 
388   return g_strcmp0 (self->arch, system_arch) == 0;
389 }
390