1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
4 * Copyright (C) Naba Kumar <naba@gnome.org>
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 2 of the License, or
9 * (at your option) any later version.
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.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 * SECTION:anjuta-utils
24 * @short_description: Utility functions
26 * @stability: Unstable
27 * @include: libanjuta/anjuta-utils.h
40 #include <sys/types.h>
41 #include <sys/fcntl.h>
42 #include <sys/termios.h>
48 #include <glib/gi18n.h>
51 #include <libgnome/gnome-util.h>
53 #include <libanjuta/anjuta-utils.h>
54 #include <libanjuta/anjuta-debug.h>
56 #include <libgnomevfs/gnome-vfs.h>
58 #define FILE_BUFFER_SIZE 1024
61 anjuta_util_copy_file (gchar
* src
, gchar
* dest
, gboolean show_error
)
63 FILE *input_fp
, *output_fp
;
64 gchar buffer
[FILE_BUFFER_SIZE
];
65 gint bytes_read
, bytes_written
;
70 input_fp
= fopen (src
, "rb");
74 anjuta_util_dialog_error_system (NULL
, errno
,
75 _("Unable to read file: %s."),
80 output_fp
= fopen (dest
, "wb");
81 if (output_fp
== NULL
)
84 anjuta_util_dialog_error_system (NULL
, errno
,
85 _("Unable to create file: %s."),
93 bytes_read
= fread (buffer
, 1, FILE_BUFFER_SIZE
, input_fp
);
94 if (bytes_read
!= FILE_BUFFER_SIZE
&& ferror (input_fp
))
102 bytes_written
= fwrite (buffer
, 1, bytes_read
, output_fp
);
103 if (bytes_read
!= bytes_written
)
110 if (bytes_read
!= FILE_BUFFER_SIZE
&& feof (input_fp
))
119 if( show_error
&& (error
== FALSE
))
120 anjuta_util_dialog_error_system (NULL
, errno
,
121 _("Unable to complete file copy"));
126 anjuta_util_color_from_string (const gchar
* val
, guint16
* r
, guint16
* g
, guint16
* b
)
129 if (gdk_color_parse(val
, &color
))
138 anjuta_util_string_from_color (guint16 r
, guint16 g
, guint16 b
)
140 return g_strdup_printf("#%02x%02x%02x", r
>> 8, g
>> 8, b
>> 8);
143 /* Get a GdkColor from preferences. Free the color with gdk_color_free() */
145 anjuta_util_convert_color(AnjutaPreferences
* prefs
, const gchar
* pref_name
)
147 GdkColor
* color
= g_new0(GdkColor
, 1);
148 gchar
* color_string
= anjuta_preferences_get(prefs
, pref_name
);
149 gdk_color_parse(color_string
, color
);
154 anjuta_util_button_new_with_stock_image (const gchar
* text
,
155 const gchar
* stock_id
)
164 button
= gtk_button_new ();
166 if (GTK_BIN (button
)->child
)
167 gtk_container_remove (GTK_CONTAINER (button
),
168 GTK_BIN (button
)->child
);
170 if (gtk_stock_lookup (stock_id
, &item
))
172 label
= gtk_label_new_with_mnemonic (text
);
174 gtk_label_set_mnemonic_widget (GTK_LABEL (label
), GTK_WIDGET (button
));
176 image
= gtk_image_new_from_stock (stock_id
, GTK_ICON_SIZE_BUTTON
);
177 hbox
= gtk_hbox_new (FALSE
, 2);
179 align
= gtk_alignment_new (0.5, 0.5, 0.0, 0.0);
181 gtk_box_pack_start (GTK_BOX (hbox
), image
, FALSE
, FALSE
, 0);
182 gtk_box_pack_end (GTK_BOX (hbox
), label
, FALSE
, FALSE
, 0);
184 gtk_container_add (GTK_CONTAINER (button
), align
);
185 gtk_container_add (GTK_CONTAINER (align
), hbox
);
186 gtk_widget_show_all (align
);
191 label
= gtk_label_new_with_mnemonic (text
);
192 gtk_label_set_mnemonic_widget (GTK_LABEL (label
), GTK_WIDGET (button
));
194 gtk_misc_set_alignment (GTK_MISC (label
), 0.5, 0.5);
196 gtk_widget_show (label
);
197 gtk_container_add (GTK_CONTAINER (button
), label
);
203 anjuta_util_dialog_add_button (GtkDialog
*dialog
, const gchar
* text
,
204 const gchar
* stock_id
, gint response_id
)
208 g_return_val_if_fail (GTK_IS_DIALOG (dialog
), NULL
);
209 g_return_val_if_fail (text
!= NULL
, NULL
);
210 g_return_val_if_fail (stock_id
!= NULL
, NULL
);
212 button
= anjuta_util_button_new_with_stock_image (text
, stock_id
);
213 g_return_val_if_fail (button
!= NULL
, NULL
);
215 GTK_WIDGET_SET_FLAGS (button
, GTK_CAN_DEFAULT
);
217 gtk_widget_show (button
);
219 gtk_dialog_add_action_widget (dialog
, button
, response_id
);
225 anjuta_util_dialog_error (GtkWindow
*parent
, const gchar
*mesg
, ...)
230 GtkWindow
*real_parent
;
232 va_start (args
, mesg
);
233 message
= g_strdup_vprintf (mesg
, args
);
236 if (parent
&& GTK_IS_WINDOW (parent
))
238 real_parent
= parent
;
245 // Dialog to be HIG compliant
246 dialog
= gtk_message_dialog_new (real_parent
,
247 GTK_DIALOG_DESTROY_WITH_PARENT
,
249 GTK_BUTTONS_CLOSE
, message
);
250 g_signal_connect (G_OBJECT (dialog
), "response",
251 G_CALLBACK (gtk_widget_destroy
), NULL
);
252 gtk_widget_show (dialog
);
257 anjuta_util_dialog_warning (GtkWindow
*parent
, const gchar
* mesg
, ...)
262 GtkWindow
*real_parent
;
264 va_start (args
, mesg
);
265 message
= g_strdup_vprintf (mesg
, args
);
268 if (parent
&& GTK_IS_WINDOW (parent
))
270 real_parent
= parent
;
277 // Dialog to be HIG compliant
278 dialog
= gtk_message_dialog_new (real_parent
,
279 GTK_DIALOG_DESTROY_WITH_PARENT
,
281 GTK_BUTTONS_CLOSE
, message
);
282 g_signal_connect (G_OBJECT (dialog
), "response",
283 G_CALLBACK (gtk_widget_destroy
), NULL
);
284 gtk_widget_show (dialog
);
289 anjuta_util_dialog_info (GtkWindow
*parent
, const gchar
* mesg
, ...)
294 GtkWindow
*real_parent
;
296 va_start (args
, mesg
);
297 message
= g_strdup_vprintf (mesg
, args
);
300 if (parent
&& GTK_IS_WINDOW (parent
))
302 real_parent
= parent
;
308 // Dialog to be HIG compliant
309 dialog
= gtk_message_dialog_new (real_parent
,
310 GTK_DIALOG_DESTROY_WITH_PARENT
,
312 GTK_BUTTONS_CLOSE
, message
);
313 g_signal_connect (G_OBJECT (dialog
), "response",
314 G_CALLBACK (gtk_widget_destroy
), NULL
);
315 gtk_widget_show (dialog
);
320 anjuta_util_dialog_error_system (GtkWindow
* parent
, gint errnum
,
321 const gchar
* mesg
, ... )
327 GtkWindow
*real_parent
;
329 va_start (args
, mesg
);
330 message
= g_strdup_vprintf (mesg
, args
);
334 tot_mesg
= g_strconcat (message
, _("\nSystem: "),
335 g_strerror(errnum
), NULL
);
340 if (parent
&& GTK_IS_WINDOW (parent
))
342 real_parent
= parent
;
348 // Dialog to be HIG compliant
349 dialog
= gtk_message_dialog_new (real_parent
,
350 GTK_DIALOG_DESTROY_WITH_PARENT
,
352 GTK_BUTTONS_CLOSE
, tot_mesg
);
353 g_signal_connect (G_OBJECT (dialog
), "response",
354 G_CALLBACK (gtk_widget_destroy
), NULL
);
355 gtk_widget_show (dialog
);
360 anjuta_util_dialog_boolean_question (GtkWindow
*parent
, const gchar
*mesg
, ...)
366 GtkWindow
*real_parent
;
368 va_start (args
, mesg
);
369 message
= g_strdup_vprintf (mesg
, args
);
372 if (parent
&& GTK_IS_WINDOW (parent
))
374 real_parent
= parent
;
381 dialog
= gtk_message_dialog_new (real_parent
,
382 GTK_DIALOG_DESTROY_WITH_PARENT
,
383 GTK_MESSAGE_QUESTION
,
384 GTK_BUTTONS_YES_NO
, message
);
386 ret
= gtk_dialog_run (GTK_DIALOG (dialog
));
387 gtk_widget_destroy (dialog
);
390 return (ret
== GTK_RESPONSE_YES
);
394 anjuta_util_dialog_input (GtkWindow
*parent
, const gchar
*prompt
,
395 const gchar
*default_value
, gchar
**return_value
)
397 GtkWidget
*dialog
, *label
, *frame
, *entry
, *dialog_vbox
, *vbox
;
400 GtkWindow
*real_parent
;
402 if (parent
&& GTK_IS_WINDOW (parent
))
404 real_parent
= parent
;
411 dialog
= gtk_dialog_new_with_buttons (prompt
, real_parent
,
412 GTK_DIALOG_DESTROY_WITH_PARENT
,
413 GTK_STOCK_CANCEL
, GTK_RESPONSE_CANCEL
,
414 GTK_STOCK_OK
, GTK_RESPONSE_OK
,
416 gtk_dialog_set_default_response (GTK_DIALOG (dialog
), GTK_RESPONSE_OK
);
417 dialog_vbox
= GTK_DIALOG (dialog
)->vbox
;
418 gtk_window_set_default_size (GTK_WINDOW (dialog
), 400, -1);
419 gtk_widget_show (dialog_vbox
);
421 markup
= g_strconcat ("<b>", prompt
, "</b>", NULL
);
422 label
= gtk_label_new (NULL
);
423 gtk_label_set_markup (GTK_LABEL (label
), markup
);
424 gtk_widget_show (label
);
427 frame
= gtk_frame_new (NULL
);
428 gtk_frame_set_label_widget (GTK_FRAME (frame
), label
);
429 gtk_frame_set_shadow_type (GTK_FRAME (frame
), GTK_SHADOW_NONE
);
430 gtk_container_set_border_width (GTK_CONTAINER (frame
), 10);
431 gtk_widget_show (frame
);
432 gtk_box_pack_start (GTK_BOX (dialog_vbox
), frame
, FALSE
, FALSE
, 0);
434 vbox
= gtk_vbox_new (FALSE
, 0);
435 gtk_widget_show (vbox
);
436 gtk_container_set_border_width (GTK_CONTAINER (vbox
), 10);
437 gtk_container_add (GTK_CONTAINER (frame
), vbox
);
439 entry
= gtk_entry_new ();
440 gtk_widget_show (entry
);
441 gtk_entry_set_activates_default (GTK_ENTRY (entry
), TRUE
);
442 gtk_box_pack_start (GTK_BOX (vbox
), entry
, FALSE
, FALSE
, 0);
444 gtk_entry_set_text (GTK_ENTRY (entry
), default_value
);
446 res
= gtk_dialog_run (GTK_DIALOG (dialog
));
448 if (gtk_entry_get_text (GTK_ENTRY (entry
)) &&
449 strlen (gtk_entry_get_text (GTK_ENTRY (entry
))) > 0)
451 *return_value
= g_strdup (gtk_entry_get_text (GTK_ENTRY (entry
)));
455 *return_value
= NULL
;
457 gtk_widget_destroy (dialog
);
458 return (res
== GTK_RESPONSE_OK
);
462 anjuta_util_prog_is_installed (gchar
* prog
, gboolean show
)
464 gchar
* prog_path
= g_find_program_in_path (prog
);
472 anjuta_util_dialog_error (NULL
, _("The \"%s\" utility is not installed.\n"
473 "Please install it."), prog
);
479 anjuta_util_get_a_tmp_file (void)
481 static gint count
= 0;
485 tmpdir
= g_get_tmp_dir ();
487 g_strdup_printf ("%s/anjuta_%d.%d", tmpdir
, count
++, getpid ());
491 /* GList of strings operations */
493 anjuta_util_glist_from_string (const gchar
*string
)
495 gchar
*str
, *temp
, buff
[256];
497 gchar
*word_start
, *word_end
;
502 temp
= g_strdup (string
);
512 /* Remove leading spaces */
513 while (isspace (*str
) && *str
!= '\0')
518 /* Find start and end of word */
520 while (!isspace (*str
) && *str
!= '\0')
524 /* Copy the word into the buffer */
525 for (ptr
= word_start
, i
= 0; ptr
< word_end
; ptr
++, i
++)
529 list
= g_list_append (list
, g_strdup (buff
));
538 /* Prefix the strings */
540 anjuta_util_glist_strings_prefix (GList
* list
, const gchar
*prefix
)
545 g_return_if_fail (prefix
!= NULL
);
550 node
->data
= g_strconcat (prefix
, tmp
, NULL
);
551 if (tmp
) g_free (tmp
);
552 node
= g_list_next (node
);
556 /* Suffix the strings */
558 anjuta_util_glist_strings_sufix (GList
* list
, const gchar
*sufix
)
563 g_return_if_fail (sufix
!= NULL
);
568 node
->data
= g_strconcat (tmp
, sufix
, NULL
);
569 if (tmp
) g_free (tmp
);
570 node
= g_list_next (node
);
574 /* Duplicate list of strings */
576 anjuta_util_glist_strings_dup (GList
* list
)
586 new_list
= g_list_append (new_list
, g_strdup(node
->data
));
588 new_list
= g_list_append (new_list
, NULL
);
589 node
= g_list_next (node
);
595 anjuta_util_get_real_path (const gchar
*path
)
601 gchar buf
[PATH_MAX
+1];
603 result
= realpath (path
, buf
);
606 *(buf
+ PATH_MAX
) = '\0'; /* ensure a terminator */
607 return g_strdup (buf
);
611 /* the string returned by realpath should be cleaned with
612 free(), not g_free() */
613 buf
= realpath (path
, NULL
);
616 result
= g_strdup (buf
);
625 /* Dedup a list of paths - duplicates are removed from the tail.
626 ** Useful for deduping Recent Files and Recent Projects */
628 anjuta_util_glist_path_dedup(GList
*list
)
630 GList
*nlist
= NULL
, *tmp
, *tmp1
;
633 for (tmp
= list
; tmp
; tmp
= g_list_next(tmp
))
635 path
= anjuta_util_get_real_path ((const gchar
*) tmp
->data
);
638 if (stat (path
, &s
) != 0)
644 for (tmp1
= nlist
; tmp1
; tmp1
= g_list_next(tmp1
))
646 if (0 == strcmp((const char *) tmp1
->data
, path
))
654 nlist
= g_list_prepend(nlist
, path
);
658 anjuta_util_glist_strings_free(list
);
659 nlist
= g_list_reverse(nlist
);
664 sort_node (gchar
* a
, gchar
*b
)
666 if ( !a
&& !b
) return 0;
667 else if (!a
) return -1;
668 else if (!b
) return 1;
669 return strcmp (a
, b
);
672 /* Sort the list alphabatically */
674 anjuta_util_glist_strings_sort (GList
* list
)
676 return g_list_sort(list
, (GCompareFunc
)sort_node
);
679 /* Free the strings and GList */
681 anjuta_util_glist_strings_free (GList
* list
)
689 node
= g_list_next (node
);
695 anjuta_util_type_from_string (AnjutaUtilStringMap
*map
, const char *str
)
699 while (-1 != map
[i
].type
)
701 if (0 == strcmp(map
[i
].name
, str
))
709 anjuta_util_string_from_type (AnjutaUtilStringMap
*map
, int type
)
712 while (-1 != map
[i
].type
)
714 if (map
[i
].type
== type
)
722 anjuta_util_glist_from_map (AnjutaUtilStringMap
*map
)
724 GList
*out_list
= NULL
;
726 while (-1 != map
[i
].type
)
728 out_list
= g_list_append(out_list
, map
[i
].name
);
736 anjuta_util_update_string_list (GList
*p_list
, const gchar
*p_str
, gint length
)
742 for (i
= 0; i
< g_list_length (p_list
); i
++)
744 str
= (gchar
*) g_list_nth_data (p_list
, i
);
747 if (strcmp (p_str
, str
) == 0)
749 p_list
= g_list_remove (p_list
, str
);
750 p_list
= g_list_prepend (p_list
, str
);
754 p_list
= g_list_prepend (p_list
, g_strdup (p_str
));
755 while (g_list_length (p_list
) > length
)
757 str
= g_list_nth_data (p_list
, g_list_length (p_list
) - 1);
758 p_list
= g_list_remove (p_list
, str
);
765 anjuta_util_create_dir (const gchar
* d
)
767 if (g_file_test (d
, G_FILE_TEST_IS_DIR
))
775 anjuta_util_execute_shell (const gchar
*dir
, const gchar
*command
)
780 g_return_val_if_fail (command
!= NULL
, -1);
782 shell
= gnome_util_user_shell ();
788 anjuta_util_create_dir (dir
);
791 execlp (shell
, shell
, "-c", command
, NULL
);
792 g_warning (_("Cannot execute command: %s (using shell %s)\n"), command
, shell
);
796 g_warning (_("Cannot execute command %s (using shell %s)\n"), command
, shell
);
798 // Anjuta will take care of child exit automatically.
803 anjuta_util_convert_to_utf8 (const gchar
*str
)
805 GError
*error
= NULL
;
806 gchar
*utf8_msg_string
= NULL
;
808 g_return_val_if_fail (str
!= NULL
, NULL
);
809 g_return_val_if_fail (strlen (str
) > 0, NULL
);
811 if (g_utf8_validate(str
, -1, NULL
))
813 utf8_msg_string
= g_strdup (str
);
817 gsize rbytes
, wbytes
;
818 utf8_msg_string
= g_locale_to_utf8 (str
, -1, &rbytes
, &wbytes
, &error
);
820 g_warning ("g_locale_to_utf8 failed: %s\n", error
->message
);
821 g_error_free (error
);
822 /* g_free (utf8_msg_string);
826 return utf8_msg_string
;
830 anjuta_util_parse_args_from_string (const gchar
* string
)
834 gboolean is_quote
= FALSE
;
835 gchar
* buffer
= g_new0(gchar
, strlen(string
) + 1);
852 /* The current char was escaped */
855 } else if (*s
== '\\') {
856 /* Current char is an escape */
858 } else if (is_quote
&& *s
== quote
) {
859 /* Current char ends a quotation */
861 if (!isspace(*(s
+1)) && (*(s
+1) != '\0')) {
862 /* If there is no space after the quotation or it is not
863 the end of the string */
864 g_warning ("Parse error while parsing program arguments");
866 } else if ((*s
== '\"' || *s
== '\'')) {
868 /* Current char starts a quotation */
872 /* Just a quote char inside quote */
875 } else if (is_quote
){
876 /* Any other char inside quote */
878 } else if (isspace(*s
)) {
879 /* Any white space outside quote */
881 buffer
[idx
++] = '\0';
882 args
= g_list_append (args
, g_strdup (buffer
));
891 /* There are chars in the buffer. Flush as the last arg */
892 buffer
[idx
++] = '\0';
893 args
= g_list_append (args
, g_strdup (buffer
));
897 g_warning ("Unclosed quotation encountered at the end of parsing");
903 anjuta_util_escape_quotes(const gchar
* str
)
907 const gchar
*s
= str
;
909 g_return_val_if_fail(str
, NULL
);
912 /* We are assuming there will be less than 2048 chars to escape */
913 max_size
= strlen(str
) + 2048;
914 buffer
= g_new (gchar
, max_size
);
920 if (*s
== '\"' || *s
== '\'' || *s
== '\\')
921 buffer
[idx
++] = '\\';
929 /* Diff the text contained in uri with text. Return true if files
930 differ, FALSE if they are identical.
931 FIXME: Find a better algorithm, this seems ineffective */
933 gboolean
anjuta_util_diff(const gchar
* uri
, const gchar
* text
)
935 GnomeVFSFileSize bytes_read
;
937 GnomeVFSFileInfo info
;
938 GnomeVFSHandle
* handle
= NULL
;
940 gnome_vfs_get_file_info(uri
, &info
, GNOME_VFS_FILE_INFO_DEFAULT
);
942 if (info
.size
== 0 && text
== NULL
)
944 else if (info
.size
== 0 || text
== NULL
)
947 file_text
= g_new0(gchar
, info
.size
+ 1);
949 if (gnome_vfs_open(&handle
, uri
, GNOME_VFS_OPEN_READ
!= GNOME_VFS_OK
))
952 if ((gnome_vfs_read(handle
, file_text
, info
.size
, &bytes_read
) == GNOME_VFS_OK
)
953 && (bytes_read
== info
.size
))
955 gnome_vfs_close(handle
);
957 if ((g_utf8_strlen(file_text
, -1) == g_utf8_strlen(text
, -1))
958 && strcmp(file_text
, text
) == 0)
964 gnome_vfs_close(handle
);
970 anjuta_util_path_has_extension (const gchar
*path
, const gchar
*ext
)
972 if (strlen (path
) <= strlen (ext
))
974 if ((path
[strlen (path
) - strlen (ext
) - 1] == '.') &&
975 (strcmp (&path
[strlen (path
) - strlen (ext
)], ext
) == 0))
981 anjuta_util_get_uri_mime_type (const gchar
*uri
)
983 GnomeVFSURI
*vfs_uri
;
987 g_return_val_if_fail (uri
!= NULL
, NULL
);
989 vfs_uri
= gnome_vfs_uri_new (uri
);
991 path
= gnome_vfs_uri_get_path (vfs_uri
);
995 /* If Anjuta is not installed in system gnome prefix, the mime types
996 * may not have been correctly registed. In that case, we use the
997 * following mime detection
1001 mime_type
= gnome_vfs_get_mime_type (uri
);
1003 else if (anjuta_util_path_has_extension (path
, "anjuta"))
1005 mime_type
= g_strdup ("application/x-anjuta");
1007 else if (anjuta_util_path_has_extension (path
, "prj"))
1009 mime_type
= g_strdup ("application/x-anjuta-old");
1011 else if (anjuta_util_path_has_extension (path
, "ui"))
1013 mime_type
= g_strdup ("text/xml");
1015 else if (anjuta_util_path_has_extension (path
, "glade"))
1017 mime_type
= g_strdup ("application/x-glade");
1021 mime_type
= gnome_vfs_get_mime_type (uri
);
1025 gnome_vfs_uri_unref (vfs_uri
);
1029 #ifndef HAVE_LIBUTIL
1032 static int ptym_open (char *pts_name
);
1033 static int ptys_open (int fdm
, char * pts_name
);
1036 login_tty(int ttyfd
)
1048 /* First disconnect from the old controlling tty. */
1050 fd
= open("/dev/tty", O_RDWR
|O_NOCTTY
);
1053 ioctl(fd
, TIOCNOTTY
, NULL
);
1057 //syslog(LOG_WARNING, "NO CTTY");
1058 #endif /* TIOCNOTTY */
1060 /* Verify that we are successfully disconnected from the controlling tty. */
1061 fd
= open("/dev/tty", O_RDWR
|O_NOCTTY
);
1064 //syslog(LOG_WARNING, "Failed to disconnect from controlling tty.");
1068 /* Make it our controlling tty. */
1070 ioctl(ttyfd
, TIOCSCTTY
, NULL
);
1071 #endif /* TIOCSCTTY */
1073 fdname
= ttyname (ttyfd
);
1074 fd
= open(fdname
, O_RDWR
);
1076 ;//syslog(LOG_WARNING, "open %s: %s", fdname, strerror(errno));
1080 /* Verify that we now have a controlling tty. */
1081 fd
= open("/dev/tty", O_WRONLY
);
1084 //syslog(LOG_WARNING, "open /dev/tty: %s", strerror(errno));
1089 #if defined(HAVE_VHANGUP) && !defined(HAVE_REVOKE)
1091 RETSIGTYPE (*sig
)();
1092 sig
= signal(SIGHUP
, SIG_IGN
);
1094 signal(SIGHUP
, sig
);
1097 fd
= open(fdname
, O_RDWR
);
1100 //syslog(LOG_ERR, "can't reopen ctty %s: %s", fdname, strerror(errno));
1122 openpty(int *amaster
, int *aslave
, char *name
, struct termios
*termp
,
1123 struct winsize
*winp
)
1126 *amaster
= ptym_open(line
);
1129 *aslave
= ptys_open(*amaster
, line
);
1137 #define TCSAFLUSH TCSETAF
1140 (void) tcsetattr(*aslave
, TCSAFLUSH
, termp
);
1143 (void) ioctl(*aslave
, TIOCSWINSZ
, (char *)winp
);
1149 ptym_open(char * pts_name
)
1155 strcpy(pts_name
, "/dev/ptmx");
1156 fdm
= open(pts_name
, O_RDWR
);
1159 if (grantpt(fdm
) < 0) { /* grant access to slave */
1163 if (unlockpt(fdm
) < 0) { /* clear slave's lock flag */
1168 if (ptr
== NULL
) { /* get slave's name */
1172 strcpy(pts_name
, ptr
); /* return name of slave */
1173 return fdm
; /* return fd of master */
1177 strcpy(pts_name
, "/dev/ptyXY");
1178 /* array index: 012345689 (for references in following code) */
1179 for (ptr1
= "pqrstuvwxyzPQRST"; *ptr1
!= 0; ptr1
++) {
1180 pts_name
[8] = *ptr1
;
1181 for (ptr2
= "0123456789abcdef"; *ptr2
!= 0; ptr2
++) {
1182 pts_name
[9] = *ptr2
;
1183 /* try to open master */
1184 fdm
= open(pts_name
, O_RDWR
);
1186 if (errno
== ENOENT
) /* different from EIO */
1187 return -1; /* out of pty devices */
1189 continue; /* try next pty device */
1191 pts_name
[5] = 't'; /* chage "pty" to "tty" */
1192 return fdm
; /* got it, return fd of master */
1195 return -1; /* out of pty devices */
1200 ptys_open(int fdm
, char * pts_name
)
1204 /* following should allocate controlling terminal */
1205 fds
= open(pts_name
, O_RDWR
);
1210 if (ioctl(fds
, I_PUSH
, "ptem") < 0) {
1215 if (ioctl(fds
, I_PUSH
, "ldterm") < 0) {
1220 if (ioctl(fds
, I_PUSH
, "ttcompat") < 0) {
1226 if (ioctl(fdm
, I_PUSH
, "pckt") < 0) {
1232 if (ioctl(fdm
, I_SRDOPT
, RMSGN
|RPROTDAT
) < 0) {
1241 struct group
*grptr
;
1243 grptr
= getgrnam("tty");
1245 gid
= grptr
->gr_gid
;
1247 gid
= -1; /* group tty is not in the group file */
1248 /* following two functions don't work unless we're root */
1249 chown(pts_name
, getuid(), gid
);
1250 chmod(pts_name
, S_IRUSR
| S_IWUSR
| S_IWGRP
);
1251 fds
= open(pts_name
, O_RDWR
);
1261 forkpty(int *amaster
, char *name
, struct termios
*termp
, struct winsize
*winp
)
1263 int master
, slave
, pid
;
1265 if (openpty(&master
, &slave
, name
, termp
, winp
) == -1)
1267 switch (pid
= fork()) {
1286 int scandir(const char *dir
, struct dirent
***namelist
,
1287 int (*select
)(const struct dirent
*),
1288 int (*compar
)(const struct dirent
**, const struct dirent
**))
1291 struct dirent
*entry
;
1295 if ((d
=opendir(dir
)) == NULL
)
1299 while ((entry
=readdir(d
)) != NULL
)
1301 if (select
== NULL
|| (select
!= NULL
&& (*select
)(entry
)))
1303 *namelist
=(struct dirent
**)realloc((void *)(*namelist
),
1304 (size_t)((i
+1)*sizeof(struct dirent
*)));
1305 if (*namelist
== NULL
) return(-1);
1306 entrysize
=sizeof(struct dirent
)-sizeof(entry
->d_name
)+strlen(entry
->d_name
)+1;
1307 (*namelist
)[i
]=(struct dirent
*)malloc(entrysize
);
1308 if ((*namelist
)[i
] == NULL
) return(-1);
1309 memcpy((*namelist
)[i
], entry
, entrysize
);
1313 if (closedir(d
)) return(-1);
1314 if (i
== 0) return(-1);
1316 qsort((void *)(*namelist
), (size_t)i
, sizeof(struct dirent
*), compar
);
1321 #endif /* HAVE_LIBUTIL */