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
);
610 /* strictly, the string returned from this should be cleaned with
611 free(), not g_free() */
612 return (realpath (path
, NULL
));
618 /* Dedup a list of paths - duplicates are removed from the tail.
619 ** Useful for deduping Recent Files and Recent Projects */
621 anjuta_util_glist_path_dedup(GList
*list
)
623 GList
*nlist
= NULL
, *tmp
, *tmp1
;
626 for (tmp
= list
; tmp
; tmp
= g_list_next(tmp
))
628 path
= anjuta_util_get_real_path ((const gchar
*) tmp
->data
);
631 if (stat (path
, &s
) != 0)
637 for (tmp1
= nlist
; tmp1
; tmp1
= g_list_next(tmp1
))
639 if (0 == strcmp((const char *) tmp1
->data
, path
))
647 nlist
= g_list_prepend(nlist
, path
);
651 anjuta_util_glist_strings_free(list
);
652 nlist
= g_list_reverse(nlist
);
657 sort_node (gchar
* a
, gchar
*b
)
659 if ( !a
&& !b
) return 0;
660 else if (!a
) return -1;
661 else if (!b
) return 1;
662 return strcmp (a
, b
);
665 /* Sort the list alphabatically */
667 anjuta_util_glist_strings_sort (GList
* list
)
669 return g_list_sort(list
, (GCompareFunc
)sort_node
);
672 /* Free the strings and GList */
674 anjuta_util_glist_strings_free (GList
* list
)
682 node
= g_list_next (node
);
688 anjuta_util_type_from_string (AnjutaUtilStringMap
*map
, const char *str
)
692 while (-1 != map
[i
].type
)
694 if (0 == strcmp(map
[i
].name
, str
))
702 anjuta_util_string_from_type (AnjutaUtilStringMap
*map
, int type
)
705 while (-1 != map
[i
].type
)
707 if (map
[i
].type
== type
)
715 anjuta_util_glist_from_map (AnjutaUtilStringMap
*map
)
717 GList
*out_list
= NULL
;
719 while (-1 != map
[i
].type
)
721 out_list
= g_list_append(out_list
, map
[i
].name
);
729 anjuta_util_update_string_list (GList
*p_list
, const gchar
*p_str
, gint length
)
735 for (i
= 0; i
< g_list_length (p_list
); i
++)
737 str
= (gchar
*) g_list_nth_data (p_list
, i
);
740 if (strcmp (p_str
, str
) == 0)
742 p_list
= g_list_remove (p_list
, str
);
743 p_list
= g_list_prepend (p_list
, str
);
747 p_list
= g_list_prepend (p_list
, g_strdup (p_str
));
748 while (g_list_length (p_list
) > length
)
750 str
= g_list_nth_data (p_list
, g_list_length (p_list
) - 1);
751 p_list
= g_list_remove (p_list
, str
);
758 anjuta_util_create_dir (const gchar
* d
)
760 if (g_file_test (d
, G_FILE_TEST_IS_DIR
))
768 anjuta_util_execute_shell (const gchar
*dir
, const gchar
*command
)
773 g_return_val_if_fail (command
!= NULL
, -1);
775 shell
= gnome_util_user_shell ();
781 anjuta_util_create_dir (dir
);
784 execlp (shell
, shell
, "-c", command
, NULL
);
785 g_warning (_("Cannot execute command: %s (using shell %s)\n"), command
, shell
);
789 g_warning (_("Cannot execute command %s (using shell %s)\n"), command
, shell
);
791 // Anjuta will take care of child exit automatically.
796 anjuta_util_convert_to_utf8 (const gchar
*str
)
798 GError
*error
= NULL
;
799 gchar
*utf8_msg_string
= NULL
;
801 g_return_val_if_fail (str
!= NULL
, NULL
);
802 g_return_val_if_fail (strlen (str
) > 0, NULL
);
804 if (g_utf8_validate(str
, -1, NULL
))
806 utf8_msg_string
= g_strdup (str
);
810 gsize rbytes
, wbytes
;
811 utf8_msg_string
= g_locale_to_utf8 (str
, -1, &rbytes
, &wbytes
, &error
);
813 g_warning ("g_locale_to_utf8 failed: %s\n", error
->message
);
814 g_error_free (error
);
815 /* g_free (utf8_msg_string);
819 return utf8_msg_string
;
823 anjuta_util_parse_args_from_string (const gchar
* string
)
827 gboolean is_quote
= FALSE
;
828 gchar
* buffer
= g_new0(gchar
, strlen(string
) + 1);
845 /* The current char was escaped */
848 } else if (*s
== '\\') {
849 /* Current char is an escape */
851 } else if (*s
== quote
) {
852 /* Current char ends a quotation */
854 if (!isspace(*(s
+1)) && (*(s
+1) != '\0')) {
855 /* If there is no space after the quotation or it is not
856 the end of the string */
857 g_warning ("Parse error while parsing program arguments");
859 } else if ((*s
== '\"' || *s
== '\'')) {
861 /* Current char starts a quotation */
865 /* Just a quote char inside quote */
868 } else if (is_quote
){
869 /* Any other char inside quote */
871 } else if (isspace(*s
)) {
872 /* Any white space outside quote */
874 buffer
[idx
++] = '\0';
875 args
= g_list_append (args
, g_strdup (buffer
));
884 /* There are chars in the buffer. Flush as the last arg */
885 buffer
[idx
++] = '\0';
886 args
= g_list_append (args
, g_strdup (buffer
));
890 g_warning ("Unclosed quotation encountered at the end of parsing");
896 anjuta_util_escape_quotes(const gchar
* str
)
900 const gchar
*s
= str
;
902 g_return_val_if_fail(str
, NULL
);
905 /* We are assuming there will be less than 2048 chars to escape */
906 max_size
= strlen(str
) + 2048;
907 buffer
= g_new (gchar
, max_size
);
913 if (*s
== '\"' || *s
== '\'' || *s
== '\\')
914 buffer
[idx
++] = '\\';
922 /* Diff the text contained in uri with text. Return true if files
923 differ, FALSE if they are identical.
924 FIXME: Find a better algorithm, this seems ineffective */
926 gboolean
anjuta_util_diff(const gchar
* uri
, const gchar
* text
)
928 GnomeVFSFileSize bytes_read
;
930 GnomeVFSFileInfo info
;
931 GnomeVFSHandle
* handle
= NULL
;
933 gnome_vfs_get_file_info(uri
, &info
, GNOME_VFS_FILE_INFO_DEFAULT
);
935 if (info
.size
== 0 && text
== NULL
)
937 else if (info
.size
== 0 || text
== NULL
)
940 file_text
= g_new0(gchar
, info
.size
+ 1);
942 if (gnome_vfs_open(&handle
, uri
, GNOME_VFS_OPEN_READ
!= GNOME_VFS_OK
))
945 if ((gnome_vfs_read(handle
, file_text
, info
.size
, &bytes_read
) == GNOME_VFS_OK
)
946 && (bytes_read
== info
.size
))
948 gnome_vfs_close(handle
);
950 if ((g_utf8_strlen(file_text
, -1) == g_utf8_strlen(text
, -1))
951 && strcmp(file_text
, text
) == 0)
957 gnome_vfs_close(handle
);
963 anjuta_util_path_has_extension (const gchar
*path
, const gchar
*ext
)
965 if (strlen (path
) <= strlen (ext
))
967 if ((path
[strlen (path
) - strlen (ext
) - 1] == '.') &&
968 (strcmp (&path
[strlen (path
) - strlen (ext
)], ext
) == 0))
974 anjuta_util_get_uri_mime_type (const gchar
*uri
)
976 GnomeVFSURI
*vfs_uri
;
980 g_return_val_if_fail (uri
!= NULL
, NULL
);
982 vfs_uri
= gnome_vfs_uri_new (uri
);
984 path
= gnome_vfs_uri_get_path (vfs_uri
);
988 /* If Anjuta is not installed in system gnome prefix, the mime types
989 * may not have been correctly registed. In that case, we use the
990 * following mime detection
994 mime_type
= gnome_vfs_get_mime_type (uri
);
996 else if (anjuta_util_path_has_extension (path
, "anjuta"))
998 mime_type
= g_strdup ("application/x-anjuta");
1000 else if (anjuta_util_path_has_extension (path
, "prj"))
1002 mime_type
= g_strdup ("application/x-anjuta-old");
1004 else if (anjuta_util_path_has_extension (path
, "ui"))
1006 mime_type
= g_strdup ("text/xml");
1008 else if (anjuta_util_path_has_extension (path
, "glade"))
1010 mime_type
= g_strdup ("application/x-glade");
1014 mime_type
= gnome_vfs_get_mime_type (uri
);
1018 gnome_vfs_uri_unref (vfs_uri
);
1022 #ifndef HAVE_LIBUTIL
1025 static int ptym_open (char *pts_name
);
1026 static int ptys_open (int fdm
, char * pts_name
);
1029 login_tty(int ttyfd
)
1041 /* First disconnect from the old controlling tty. */
1043 fd
= open("/dev/tty", O_RDWR
|O_NOCTTY
);
1046 ioctl(fd
, TIOCNOTTY
, NULL
);
1050 //syslog(LOG_WARNING, "NO CTTY");
1051 #endif /* TIOCNOTTY */
1053 /* Verify that we are successfully disconnected from the controlling tty. */
1054 fd
= open("/dev/tty", O_RDWR
|O_NOCTTY
);
1057 //syslog(LOG_WARNING, "Failed to disconnect from controlling tty.");
1061 /* Make it our controlling tty. */
1063 ioctl(ttyfd
, TIOCSCTTY
, NULL
);
1064 #endif /* TIOCSCTTY */
1066 fdname
= ttyname (ttyfd
);
1067 fd
= open(fdname
, O_RDWR
);
1069 ;//syslog(LOG_WARNING, "open %s: %s", fdname, strerror(errno));
1073 /* Verify that we now have a controlling tty. */
1074 fd
= open("/dev/tty", O_WRONLY
);
1077 //syslog(LOG_WARNING, "open /dev/tty: %s", strerror(errno));
1082 #if defined(HAVE_VHANGUP) && !defined(HAVE_REVOKE)
1084 RETSIGTYPE (*sig
)();
1085 sig
= signal(SIGHUP
, SIG_IGN
);
1087 signal(SIGHUP
, sig
);
1090 fd
= open(fdname
, O_RDWR
);
1093 //syslog(LOG_ERR, "can't reopen ctty %s: %s", fdname, strerror(errno));
1115 openpty(int *amaster
, int *aslave
, char *name
, struct termios
*termp
,
1116 struct winsize
*winp
)
1119 *amaster
= ptym_open(line
);
1122 *aslave
= ptys_open(*amaster
, line
);
1130 #define TCSAFLUSH TCSETAF
1133 (void) tcsetattr(*aslave
, TCSAFLUSH
, termp
);
1136 (void) ioctl(*aslave
, TIOCSWINSZ
, (char *)winp
);
1142 ptym_open(char * pts_name
)
1148 strcpy(pts_name
, "/dev/ptmx");
1149 fdm
= open(pts_name
, O_RDWR
);
1152 if (grantpt(fdm
) < 0) { /* grant access to slave */
1156 if (unlockpt(fdm
) < 0) { /* clear slave's lock flag */
1161 if (ptr
== NULL
) { /* get slave's name */
1165 strcpy(pts_name
, ptr
); /* return name of slave */
1166 return fdm
; /* return fd of master */
1170 strcpy(pts_name
, "/dev/ptyXY");
1171 /* array index: 012345689 (for references in following code) */
1172 for (ptr1
= "pqrstuvwxyzPQRST"; *ptr1
!= 0; ptr1
++) {
1173 pts_name
[8] = *ptr1
;
1174 for (ptr2
= "0123456789abcdef"; *ptr2
!= 0; ptr2
++) {
1175 pts_name
[9] = *ptr2
;
1176 /* try to open master */
1177 fdm
= open(pts_name
, O_RDWR
);
1179 if (errno
== ENOENT
) /* different from EIO */
1180 return -1; /* out of pty devices */
1182 continue; /* try next pty device */
1184 pts_name
[5] = 't'; /* chage "pty" to "tty" */
1185 return fdm
; /* got it, return fd of master */
1188 return -1; /* out of pty devices */
1193 ptys_open(int fdm
, char * pts_name
)
1197 /* following should allocate controlling terminal */
1198 fds
= open(pts_name
, O_RDWR
);
1203 if (ioctl(fds
, I_PUSH
, "ptem") < 0) {
1208 if (ioctl(fds
, I_PUSH
, "ldterm") < 0) {
1213 if (ioctl(fds
, I_PUSH
, "ttcompat") < 0) {
1219 if (ioctl(fdm
, I_PUSH
, "pckt") < 0) {
1225 if (ioctl(fdm
, I_SRDOPT
, RMSGN
|RPROTDAT
) < 0) {
1234 struct group
*grptr
;
1236 grptr
= getgrnam("tty");
1238 gid
= grptr
->gr_gid
;
1240 gid
= -1; /* group tty is not in the group file */
1241 /* following two functions don't work unless we're root */
1242 chown(pts_name
, getuid(), gid
);
1243 chmod(pts_name
, S_IRUSR
| S_IWUSR
| S_IWGRP
);
1244 fds
= open(pts_name
, O_RDWR
);
1254 forkpty(int *amaster
, char *name
, struct termios
*termp
, struct winsize
*winp
)
1256 int master
, slave
, pid
;
1258 if (openpty(&master
, &slave
, name
, termp
, winp
) == -1)
1260 switch (pid
= fork()) {
1279 int scandir(const char *dir
, struct dirent
***namelist
,
1280 int (*select
)(const struct dirent
*),
1281 int (*compar
)(const struct dirent
**, const struct dirent
**))
1284 struct dirent
*entry
;
1288 if ((d
=opendir(dir
)) == NULL
)
1292 while ((entry
=readdir(d
)) != NULL
)
1294 if (select
== NULL
|| (select
!= NULL
&& (*select
)(entry
)))
1296 *namelist
=(struct dirent
**)realloc((void *)(*namelist
),
1297 (size_t)((i
+1)*sizeof(struct dirent
*)));
1298 if (*namelist
== NULL
) return(-1);
1299 entrysize
=sizeof(struct dirent
)-sizeof(entry
->d_name
)+strlen(entry
->d_name
)+1;
1300 (*namelist
)[i
]=(struct dirent
*)malloc(entrysize
);
1301 if ((*namelist
)[i
] == NULL
) return(-1);
1302 memcpy((*namelist
)[i
], entry
, entrysize
);
1306 if (closedir(d
)) return(-1);
1307 if (i
== 0) return(-1);
1309 qsort((void *)(*namelist
), (size_t)i
, sizeof(struct dirent
*), compar
);
1314 #endif /* HAVE_LIBUTIL */