XmPackage stub
This commit is contained in:
parent
d34e7fdc88
commit
b3b86808ea
2
xmpackage/build.sh
Executable file
2
xmpackage/build.sh
Executable file
@ -0,0 +1,2 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
../scripts/buildapp.sh xmpackage "$@"
|
27
xmpackage/src/icons/icon.xbm
Normal file
27
xmpackage/src/icons/icon.xbm
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
#define icon_width 48
|
||||||
|
#define icon_height 48
|
||||||
|
static unsigned char icon_bits[] = {
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x78, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x78, 0x00, 0x00,
|
||||||
|
0x00, 0x80, 0x07, 0xe0, 0x03, 0x00, 0x00, 0xe0, 0x01, 0x80, 0x0e, 0x00,
|
||||||
|
0x00, 0x78, 0x00, 0x40, 0x38, 0x00, 0x00, 0x1e, 0x80, 0x31, 0x60, 0x00,
|
||||||
|
0x80, 0x07, 0x40, 0x0e, 0x80, 0x01, 0xc0, 0x01, 0x20, 0x04, 0x00, 0x03,
|
||||||
|
0xe0, 0x00, 0xc0, 0x08, 0x00, 0x07, 0x60, 0x03, 0x30, 0x07, 0x80, 0x06,
|
||||||
|
0x60, 0x0c, 0x0c, 0x00, 0x20, 0x06, 0x60, 0x30, 0x03, 0x00, 0x08, 0x06,
|
||||||
|
0x60, 0xc0, 0x06, 0x00, 0x02, 0x06, 0x60, 0x00, 0x0b, 0x80, 0x60, 0x06,
|
||||||
|
0x60, 0x00, 0x3c, 0x20, 0x58, 0x06, 0x60, 0x00, 0xf0, 0x08, 0x46, 0x06,
|
||||||
|
0x60, 0x00, 0xc0, 0x83, 0x41, 0x06, 0x60, 0x00, 0x00, 0x81, 0x60, 0x06,
|
||||||
|
0x60, 0x00, 0x00, 0x80, 0x18, 0x06, 0x60, 0x00, 0x00, 0x81, 0x06, 0x06,
|
||||||
|
0x60, 0x00, 0x00, 0x80, 0x01, 0x06, 0x60, 0x00, 0x00, 0x01, 0x00, 0x06,
|
||||||
|
0x60, 0x00, 0x00, 0x00, 0x00, 0x06, 0x60, 0x00, 0x00, 0x01, 0x00, 0x06,
|
||||||
|
0x60, 0x00, 0x00, 0x00, 0x00, 0x06, 0x60, 0x00, 0x00, 0x01, 0x02, 0x06,
|
||||||
|
0x60, 0x00, 0x00, 0x80, 0x02, 0x06, 0x60, 0x00, 0x00, 0xa1, 0x02, 0x06,
|
||||||
|
0xc0, 0x01, 0x00, 0xa8, 0x82, 0x03, 0x80, 0x07, 0x00, 0xa9, 0xe0, 0x01,
|
||||||
|
0x00, 0x1e, 0x00, 0x28, 0x78, 0x00, 0x00, 0x78, 0x00, 0x09, 0x1e, 0x00,
|
||||||
|
0x00, 0xe0, 0x01, 0x80, 0x07, 0x00, 0x00, 0x80, 0x07, 0xe1, 0x01, 0x00,
|
||||||
|
0x00, 0x00, 0x1e, 0x78, 0x00, 0x00, 0x00, 0x00, 0x78, 0x1f, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
640
xmpackage/src/main.c
Normal file
640
xmpackage/src/main.c
Normal file
@ -0,0 +1,640 @@
|
|||||||
|
#define _XOPEN_SOURCE
|
||||||
|
|
||||||
|
#include <Xm/Xm.h>
|
||||||
|
#include <Xm/MainW.h>
|
||||||
|
#include <Xm/RowColumn.h>
|
||||||
|
#include <Xm/PushB.h>
|
||||||
|
#include <Xm/Text.h>
|
||||||
|
#include <Xm/Form.h>
|
||||||
|
#include <Xm/PanedW.h>
|
||||||
|
#include <Xm/TabStack.h>
|
||||||
|
#include <Xm/List.h>
|
||||||
|
#include <Xm/Frame.h>
|
||||||
|
#include <Xm/TextF.h>
|
||||||
|
#include <Xm/Separator.h>
|
||||||
|
#include <Xm/ScrolledW.h>
|
||||||
|
#include <Xm/LabelG.h>
|
||||||
|
|
||||||
|
#include <Xmd/Icon.h>
|
||||||
|
#include <Xmd/Buffer.h>
|
||||||
|
#include <Xmd/Exec.h>
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
|
||||||
|
#include "icons/icon.xbm"
|
||||||
|
|
||||||
|
Widget createLabeledTextForm (Widget, String, String, XmString);
|
||||||
|
Widget createScrolledInfoText (Widget, String);
|
||||||
|
void selectPackage (String);
|
||||||
|
void updatePackageList (void);
|
||||||
|
void readPackageList (FILE *);
|
||||||
|
void handleListModeSelectionChange (Widget, XtPointer, XtPointer);
|
||||||
|
void handlePackageSelectionChange (Widget, XtPointer, XtPointer);
|
||||||
|
void handleSearchQueryActivate (Widget, XtPointer, XtPointer);
|
||||||
|
String parsePackageName (String);
|
||||||
|
void parseInfoOutput (FILE *, String *, String *, String *, String *);
|
||||||
|
|
||||||
|
static XtAppContext application;
|
||||||
|
static Pixmap iconPixmap;
|
||||||
|
|
||||||
|
static struct {
|
||||||
|
Widget name;
|
||||||
|
Widget description;
|
||||||
|
Widget dependencies;
|
||||||
|
Widget provides;
|
||||||
|
Widget contents;
|
||||||
|
String selected;
|
||||||
|
} packageInfo = { 0 };
|
||||||
|
|
||||||
|
static struct {
|
||||||
|
Widget query;
|
||||||
|
Widget list;
|
||||||
|
Widget modeMenu;
|
||||||
|
enum {
|
||||||
|
viewModeWorld,
|
||||||
|
viewModeInstalled,
|
||||||
|
viewModeUpgradable,
|
||||||
|
viewModeOrphaned,
|
||||||
|
viewModeSearch
|
||||||
|
} viewMode;
|
||||||
|
XmString viewModeStrings[4];
|
||||||
|
} packageList = { 0 };
|
||||||
|
|
||||||
|
int main (int argc, char *argv[]) {
|
||||||
|
Widget topLevel = XtVaAppInitialize (
|
||||||
|
&application, "PackageManager",
|
||||||
|
NULL, 0,
|
||||||
|
&argc, argv,
|
||||||
|
NULL,
|
||||||
|
XmNtitle, "Package Manager",
|
||||||
|
XmNiconName, "Package Manager",
|
||||||
|
NULL);
|
||||||
|
iconPixmap = XmdLoadBitmapIcon(topLevel, icon);
|
||||||
|
XtVaSetValues (
|
||||||
|
topLevel,
|
||||||
|
XmNiconPixmap, iconPixmap,
|
||||||
|
NULL);
|
||||||
|
Widget window = XtVaCreateManagedWidget (
|
||||||
|
"window", xmMainWindowWidgetClass, topLevel,
|
||||||
|
NULL);
|
||||||
|
Widget pane = XtVaCreateWidget (
|
||||||
|
"pane", xmPanedWindowWidgetClass, window,
|
||||||
|
XmNorientation, XmHORIZONTAL,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
/* menu bar */
|
||||||
|
XmString fileString = XmStringCreateLocalized("File");
|
||||||
|
XmString systemString = XmStringCreateLocalized("System");
|
||||||
|
XmString helpString = XmStringCreateLocalized("Help");
|
||||||
|
Widget menuBar = XmVaCreateSimpleMenuBar (
|
||||||
|
window, "menuBar",
|
||||||
|
XmVaCASCADEBUTTON, fileString, 'F',
|
||||||
|
XmVaCASCADEBUTTON, systemString, 'S',
|
||||||
|
XmVaCASCADEBUTTON, helpString, 'H',
|
||||||
|
NULL);
|
||||||
|
XmStringFree(fileString);
|
||||||
|
XmStringFree(systemString);
|
||||||
|
XmStringFree(helpString);
|
||||||
|
XtManageChild(menuBar);
|
||||||
|
|
||||||
|
/* package list pane */
|
||||||
|
Widget packageListPane = XtVaCreateWidget (
|
||||||
|
"packageListPane", xmFormWidgetClass, pane,
|
||||||
|
XmNhorizontalSpacing, 4,
|
||||||
|
XmNverticalSpacing, 4,
|
||||||
|
XmNmarginHeight, 2,
|
||||||
|
XmNmarginWidth, 2,
|
||||||
|
NULL);
|
||||||
|
XmString packageSearchLabelString = XmStringCreateLocalized("Search:");
|
||||||
|
packageList.query = createLabeledTextForm (
|
||||||
|
packageListPane,
|
||||||
|
"packageSearchLabel",
|
||||||
|
"packageSearchText",
|
||||||
|
packageSearchLabelString);
|
||||||
|
XmStringFree(packageSearchLabelString);
|
||||||
|
XtAddCallback (
|
||||||
|
packageList.query,
|
||||||
|
XmNactivateCallback, handleSearchQueryActivate,
|
||||||
|
NULL);
|
||||||
|
XtVaSetValues (
|
||||||
|
XtParent(packageList.query),
|
||||||
|
XmNrightAttachment, XmATTACH_FORM,
|
||||||
|
XmNtopAttachment, XmATTACH_FORM,
|
||||||
|
XmNleftAttachment, XmATTACH_FORM,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
/* list mode selector */
|
||||||
|
Widget listModeFrame = XtVaCreateWidget (
|
||||||
|
"listModeFrame", xmFrameWidgetClass, packageListPane,
|
||||||
|
XmNshadowType, XmSHADOW_IN,
|
||||||
|
XmNshadowThickness, 1,
|
||||||
|
XmNleftAttachment, XmATTACH_FORM,
|
||||||
|
XmNrightAttachment, XmATTACH_FORM,
|
||||||
|
XmNbottomAttachment, XmATTACH_FORM,
|
||||||
|
NULL);
|
||||||
|
Widget listModeRc = XtVaCreateWidget (
|
||||||
|
"listModeRc", xmRowColumnWidgetClass, listModeFrame,
|
||||||
|
XmNmarginWidth, 0,
|
||||||
|
XmNmarginHeight, 0,
|
||||||
|
NULL);
|
||||||
|
XmString listModeString = XmStringCreateLocalized("List:");
|
||||||
|
packageList.viewModeStrings[viewModeWorld] = XmStringCreateLocalized("World");
|
||||||
|
packageList.viewModeStrings[viewModeInstalled] = XmStringCreateLocalized("Installed");
|
||||||
|
packageList.viewModeStrings[viewModeUpgradable] = XmStringCreateLocalized("Upgradable");
|
||||||
|
packageList.viewModeStrings[viewModeOrphaned] = XmStringCreateLocalized("Orphaned");
|
||||||
|
packageList.viewModeStrings[viewModeSearch] = XmStringCreateLocalized("Search");
|
||||||
|
packageList.modeMenu = XmVaCreateSimpleOptionMenu (
|
||||||
|
listModeRc, "packageListMode",
|
||||||
|
listModeString, 'L', 0, handleListModeSelectionChange,
|
||||||
|
XmVaPUSHBUTTON, packageList.viewModeStrings[viewModeWorld], 'W', NULL, NULL,
|
||||||
|
XmVaPUSHBUTTON, packageList.viewModeStrings[viewModeInstalled], 'I', NULL, NULL,
|
||||||
|
XmVaPUSHBUTTON, packageList.viewModeStrings[viewModeUpgradable], 'U', NULL, NULL,
|
||||||
|
XmVaPUSHBUTTON, packageList.viewModeStrings[viewModeOrphaned], 'O', NULL, NULL,
|
||||||
|
XmVaPUSHBUTTON, packageList.viewModeStrings[viewModeSearch], 'S', NULL, NULL,
|
||||||
|
XmNtearOffModel, XmTEAR_OFF_ENABLED,
|
||||||
|
NULL);
|
||||||
|
XmStringFree(listModeString);
|
||||||
|
XtManageChild(packageList.modeMenu);
|
||||||
|
XtManageChild(listModeFrame);
|
||||||
|
XtManageChild(listModeRc);
|
||||||
|
|
||||||
|
/* packageList */
|
||||||
|
packageList.list = XmCreateScrolledList(packageListPane, "packageList", NULL, 0);
|
||||||
|
XtVaSetValues (
|
||||||
|
XtParent(packageList.list),
|
||||||
|
XmNtopAttachment, XmATTACH_WIDGET,
|
||||||
|
XmNtopWidget, XtParent(packageList.query),
|
||||||
|
XmNleftAttachment, XmATTACH_FORM,
|
||||||
|
XmNrightAttachment, XmATTACH_FORM,
|
||||||
|
XmNbottomAttachment, XmATTACH_WIDGET,
|
||||||
|
XmNbottomWidget, listModeFrame,
|
||||||
|
NULL);
|
||||||
|
XtAddCallback (
|
||||||
|
packageList.list,
|
||||||
|
XmNbrowseSelectionCallback, handlePackageSelectionChange,
|
||||||
|
NULL);
|
||||||
|
XtManageChild(packageList.list);
|
||||||
|
|
||||||
|
/* package viewer */
|
||||||
|
Widget descriptionPane = XtVaCreateWidget (
|
||||||
|
"descriptionPane", xmFormWidgetClass, pane,
|
||||||
|
XmNhorizontalSpacing, 4,
|
||||||
|
XmNverticalSpacing, 4,
|
||||||
|
XmNmarginHeight, 2,
|
||||||
|
XmNmarginWidth, 2,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
/* package actions */
|
||||||
|
Widget packageActionsFrame = XtVaCreateWidget (
|
||||||
|
"packageActionsFrame", xmFrameWidgetClass, descriptionPane,
|
||||||
|
XmNshadowType, XmSHADOW_OUT,
|
||||||
|
XmNleftAttachment, XmATTACH_FORM,
|
||||||
|
XmNrightAttachment, XmATTACH_FORM,
|
||||||
|
XmNbottomAttachment, XmATTACH_FORM,
|
||||||
|
NULL);
|
||||||
|
Widget packageActionsRc = XtVaCreateWidget (
|
||||||
|
"packageActionsRc", xmRowColumnWidgetClass, packageActionsFrame,
|
||||||
|
XmNorientation, XmHORIZONTAL,
|
||||||
|
NULL);
|
||||||
|
XmString packageAddString = XmStringCreateLocalized("Install");
|
||||||
|
Widget packageAdd = XtVaCreateManagedWidget (
|
||||||
|
"packageAdd", xmPushButtonWidgetClass, packageActionsRc,
|
||||||
|
XmNlabelString, packageAddString,
|
||||||
|
NULL);
|
||||||
|
XmStringFree(packageAddString);
|
||||||
|
XmString packageDeleteString = XmStringCreateLocalized("Remove");
|
||||||
|
XtVaCreateManagedWidget (
|
||||||
|
"packageDelete", xmPushButtonWidgetClass, packageActionsRc,
|
||||||
|
XmNlabelString, packageDeleteString,
|
||||||
|
NULL);
|
||||||
|
XmStringFree(packageDeleteString);
|
||||||
|
XmString packageUpgradeString = XmStringCreateLocalized("Upgrade");
|
||||||
|
XtVaCreateManagedWidget (
|
||||||
|
"packageUpgrade", xmPushButtonWidgetClass, packageActionsRc,
|
||||||
|
XmNlabelString, packageUpgradeString,
|
||||||
|
NULL);
|
||||||
|
XmStringFree(packageUpgradeString);
|
||||||
|
XmString packageFixString = XmStringCreateLocalized("Fix");
|
||||||
|
XtVaCreateManagedWidget (
|
||||||
|
"packageFix", xmPushButtonWidgetClass, packageActionsRc,
|
||||||
|
XmNlabelString, packageFixString,
|
||||||
|
NULL);
|
||||||
|
XmStringFree(packageFixString);
|
||||||
|
XtManageChild(packageActionsRc);
|
||||||
|
XtManageChild(packageActionsFrame);
|
||||||
|
|
||||||
|
/* visually separate package description and actions */
|
||||||
|
Widget descriptionSeparator = XtVaCreateManagedWidget (
|
||||||
|
"descriptionSeparator", xmSeparatorWidgetClass, descriptionPane,
|
||||||
|
XmNleftAttachment, XmATTACH_FORM,
|
||||||
|
XmNrightAttachment, XmATTACH_FORM,
|
||||||
|
XmNbottomAttachment, XmATTACH_WIDGET,
|
||||||
|
XmNbottomWidget, packageAdd,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
/* package description */
|
||||||
|
packageInfo.name = XtVaCreateManagedWidget (
|
||||||
|
"name", xmLabelGadgetClass, descriptionPane,
|
||||||
|
XmNleftAttachment, XmATTACH_FORM,
|
||||||
|
XmNrightAttachment, XmATTACH_FORM,
|
||||||
|
XmNtopAttachment, XmATTACH_FORM,
|
||||||
|
NULL);
|
||||||
|
Widget descriptionTabStack = XtVaCreateWidget (
|
||||||
|
"descriptionTabStack", xmTabStackWidgetClass, descriptionPane,
|
||||||
|
XmNleftAttachment, XmATTACH_FORM,
|
||||||
|
XmNrightAttachment, XmATTACH_FORM,
|
||||||
|
XmNtopAttachment, XmATTACH_WIDGET,
|
||||||
|
XmNtopWidget, packageInfo.name,
|
||||||
|
XmNbottomAttachment, XmATTACH_WIDGET,
|
||||||
|
XmNbottomWidget, descriptionSeparator,
|
||||||
|
XmNtabMarginWidth, 0,
|
||||||
|
XmNtabMarginHeight, 0,
|
||||||
|
XmNtabLabelSpacing, 0,
|
||||||
|
XmNmarginWidth, 4,
|
||||||
|
XmNmarginHeight, 4,
|
||||||
|
XmNtabMode, XmTABS_STACKED,
|
||||||
|
NULL);
|
||||||
|
packageInfo.description = createScrolledInfoText(descriptionTabStack, "Description");
|
||||||
|
packageInfo.dependencies = createScrolledInfoText(descriptionTabStack, "Dependencies");
|
||||||
|
packageInfo.provides = createScrolledInfoText(descriptionTabStack, "Provides");
|
||||||
|
packageInfo.contents = createScrolledInfoText(descriptionTabStack, "Contents");
|
||||||
|
XtManageChild(descriptionTabStack);
|
||||||
|
|
||||||
|
/* final setup */
|
||||||
|
|
||||||
|
XtManageChild(packageListPane);
|
||||||
|
XtManageChild(descriptionPane);
|
||||||
|
XtManageChild(pane);
|
||||||
|
|
||||||
|
XtVaSetValues (
|
||||||
|
window,
|
||||||
|
XmNmenuBar, menuBar,
|
||||||
|
XmNworkWindow, pane,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
updatePackageList();
|
||||||
|
selectPackage(NULL);
|
||||||
|
|
||||||
|
XtRealizeWidget(topLevel);
|
||||||
|
XtAppMainLoop(application);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget createLabeledTextForm (
|
||||||
|
Widget parent,
|
||||||
|
String labelName,
|
||||||
|
String textName,
|
||||||
|
XmString labelString
|
||||||
|
) {
|
||||||
|
Widget form = XtVaCreateWidget (
|
||||||
|
"form", xmFormWidgetClass, parent,
|
||||||
|
XmNorientation, XmHORIZONTAL,
|
||||||
|
NULL);
|
||||||
|
Widget label = XtVaCreateManagedWidget (
|
||||||
|
labelName, xmLabelGadgetClass, form,
|
||||||
|
XmNleftAttachment, XmATTACH_FORM,
|
||||||
|
XmNtopAttachment, XmATTACH_FORM,
|
||||||
|
XmNbottomAttachment, XmATTACH_FORM,
|
||||||
|
XmNlabelString, labelString,
|
||||||
|
NULL);
|
||||||
|
Widget text = XtVaCreateManagedWidget (
|
||||||
|
textName, xmTextWidgetClass, form,
|
||||||
|
XmNleftAttachment, XmATTACH_WIDGET,
|
||||||
|
XmNleftWidget, label,
|
||||||
|
XmNtopAttachment, XmATTACH_FORM,
|
||||||
|
XmNrightAttachment, XmATTACH_FORM,
|
||||||
|
XmNbottomAttachment, XmATTACH_FORM,
|
||||||
|
NULL);
|
||||||
|
XtManageChild (form);
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget createScrolledInfoText (Widget parent, String name) {
|
||||||
|
Widget scroll = XtVaCreateWidget (
|
||||||
|
name, xmScrolledWindowWidgetClass, parent,
|
||||||
|
NULL);
|
||||||
|
Widget info = XtVaCreateManagedWidget (
|
||||||
|
"info", xmTextWidgetClass, scroll,
|
||||||
|
XmNrows, 10,
|
||||||
|
XmNcolumns, 60,
|
||||||
|
XmNpaneMinimum, 35,
|
||||||
|
XmNeditMode, XmMULTI_LINE_EDIT,
|
||||||
|
XmNeditable, False,
|
||||||
|
XmNwordWrap, True,
|
||||||
|
XmNscrollHorizontal, False,
|
||||||
|
NULL);
|
||||||
|
XtManageChild(scroll);
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
|
||||||
|
void selectPackage (String name) {
|
||||||
|
if (packageInfo.selected) XtFree(packageInfo.selected);
|
||||||
|
packageInfo.selected = name;
|
||||||
|
|
||||||
|
XmString packageNameString = NULL;
|
||||||
|
|
||||||
|
if (name == NULL) {
|
||||||
|
packageNameString = XmStringCreateLocalized("No package selected");
|
||||||
|
XtVaSetValues (
|
||||||
|
packageInfo.description,
|
||||||
|
XmNvalue, "",
|
||||||
|
NULL);
|
||||||
|
} else {
|
||||||
|
/* instruct apk to describe package */
|
||||||
|
pid_t child;
|
||||||
|
FILE *stream = XmdVaPipedExecPath (
|
||||||
|
"apk", &child, "r",
|
||||||
|
"apk", "info", name, "-dswLPR", "--license",
|
||||||
|
NULL);
|
||||||
|
if (stream == NULL) {
|
||||||
|
/* TODO: error popup */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* parse data*/
|
||||||
|
String description = NULL;
|
||||||
|
String dependencies = NULL;
|
||||||
|
String provides = NULL;
|
||||||
|
String contents = NULL;
|
||||||
|
parseInfoOutput (
|
||||||
|
stream,
|
||||||
|
&description, &dependencies,
|
||||||
|
&provides, &contents);
|
||||||
|
fclose(stream);
|
||||||
|
waitpid(child, NULL, 0);
|
||||||
|
|
||||||
|
/* set tab contents to parsed data */
|
||||||
|
packageNameString = XmStringCreateLocalized(name);
|
||||||
|
XtVaSetValues (
|
||||||
|
packageInfo.description,
|
||||||
|
XmNvalue, description,
|
||||||
|
NULL);
|
||||||
|
XtVaSetValues (
|
||||||
|
packageInfo.dependencies,
|
||||||
|
XmNvalue, dependencies,
|
||||||
|
NULL);
|
||||||
|
XtVaSetValues (
|
||||||
|
packageInfo.provides,
|
||||||
|
XmNvalue, provides,
|
||||||
|
NULL);
|
||||||
|
XtVaSetValues (
|
||||||
|
packageInfo.contents,
|
||||||
|
XmNvalue, contents,
|
||||||
|
NULL);
|
||||||
|
XtFree(description);
|
||||||
|
XtFree(dependencies);
|
||||||
|
XtFree(provides);
|
||||||
|
XtFree(contents);
|
||||||
|
}
|
||||||
|
|
||||||
|
XtVaSetValues (
|
||||||
|
packageInfo.name,
|
||||||
|
XmNlabelString, packageNameString,
|
||||||
|
NULL);
|
||||||
|
XmStringFree(packageNameString);
|
||||||
|
}
|
||||||
|
|
||||||
|
void parseInfoOutput (
|
||||||
|
FILE *stream,
|
||||||
|
String *description,
|
||||||
|
String *dependencies,
|
||||||
|
String *provides,
|
||||||
|
String *contents
|
||||||
|
) {
|
||||||
|
char nullTerminator = 0;
|
||||||
|
|
||||||
|
enum {
|
||||||
|
stateSkipUntilSpace,
|
||||||
|
stateGetHeading,
|
||||||
|
stateGetSection
|
||||||
|
} state = stateSkipUntilSpace;
|
||||||
|
int consecutiveNewlines = 0;
|
||||||
|
XmdBuffer *activeBuffer = NULL;
|
||||||
|
XmdBuffer *headingBuffer = NULL;
|
||||||
|
|
||||||
|
XmdBuffer *descriptionBuffer = XmdBufferNew(char);
|
||||||
|
XmdBuffer *dependenciesBuffer = XmdBufferNew(char);
|
||||||
|
XmdBuffer *providesBuffer = XmdBufferNew(char);
|
||||||
|
XmdBuffer *contentsBuffer = XmdBufferNew(char);
|
||||||
|
|
||||||
|
int ch;
|
||||||
|
while ((ch = fgetc(stream)) != EOF) switch (state) {
|
||||||
|
/* discard stream until there is a space */
|
||||||
|
case stateSkipUntilSpace:
|
||||||
|
if (ch == ' ') {
|
||||||
|
headingBuffer = XmdBufferNew(char);
|
||||||
|
state = stateGetHeading;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* what is the next section about? */
|
||||||
|
case stateGetHeading:
|
||||||
|
if (ch == ':') {
|
||||||
|
XmdBufferPush(headingBuffer, &nullTerminator);
|
||||||
|
String heading = XmdBufferBreak(headingBuffer);
|
||||||
|
|
||||||
|
if (strcmp(heading, "depends on") == 0) {
|
||||||
|
activeBuffer = dependenciesBuffer;
|
||||||
|
} else if (strcmp(heading, "provides") == 0) {
|
||||||
|
activeBuffer = providesBuffer;
|
||||||
|
} else if (strcmp(heading, "contains") == 0) {
|
||||||
|
activeBuffer = contentsBuffer;
|
||||||
|
} else {
|
||||||
|
activeBuffer = descriptionBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
XtFree(heading);
|
||||||
|
consecutiveNewlines = 1;
|
||||||
|
state = stateGetSection;
|
||||||
|
fgetc(stream); /* skip newline */
|
||||||
|
} else {
|
||||||
|
XmdBufferPush(headingBuffer, &ch);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* read the section data into the active buffer */
|
||||||
|
case stateGetSection:
|
||||||
|
if (ch == '\n') {
|
||||||
|
if (consecutiveNewlines > 0) {
|
||||||
|
state = stateSkipUntilSpace;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
consecutiveNewlines ++;
|
||||||
|
} else {
|
||||||
|
consecutiveNewlines = 0;
|
||||||
|
}
|
||||||
|
XmdBufferPush(activeBuffer, &ch);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
XmdBufferPush(descriptionBuffer, &nullTerminator);
|
||||||
|
XmdBufferPush(dependenciesBuffer, &nullTerminator);
|
||||||
|
XmdBufferPush(providesBuffer, &nullTerminator);
|
||||||
|
XmdBufferPush(contentsBuffer, &nullTerminator);
|
||||||
|
|
||||||
|
*description = XmdBufferBreak(descriptionBuffer);
|
||||||
|
*dependencies = XmdBufferBreak(dependenciesBuffer);
|
||||||
|
*provides = XmdBufferBreak(providesBuffer);
|
||||||
|
*contents = XmdBufferBreak(contentsBuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void updatePackageList (void) {
|
||||||
|
FILE *stream = NULL;
|
||||||
|
pid_t child = 0;
|
||||||
|
|
||||||
|
switch (packageList.viewMode) {
|
||||||
|
case viewModeWorld:
|
||||||
|
stream = fopen("/etc/apk/world", "r");
|
||||||
|
break;
|
||||||
|
case viewModeInstalled:
|
||||||
|
stream = XmdVaPipedExecPath (
|
||||||
|
"apk", &child, "r",
|
||||||
|
"apk", "list", "--installed",
|
||||||
|
NULL);
|
||||||
|
break;
|
||||||
|
case viewModeUpgradable:
|
||||||
|
stream = XmdVaPipedExecPath (
|
||||||
|
"apk", &child, "r",
|
||||||
|
"apk", "list", "--upgradable",
|
||||||
|
NULL);
|
||||||
|
break;
|
||||||
|
case viewModeOrphaned:
|
||||||
|
stream = XmdVaPipedExecPath (
|
||||||
|
"apk", &child, "r",
|
||||||
|
"apk", "list", "--orphaned",
|
||||||
|
NULL);
|
||||||
|
break;
|
||||||
|
case viewModeSearch:
|
||||||
|
;String query = NULL;
|
||||||
|
XtVaGetValues (
|
||||||
|
packageList.query,
|
||||||
|
XmNvalue, &query,
|
||||||
|
NULL);
|
||||||
|
stream = XmdVaPipedExecPath (
|
||||||
|
"apk", &child, "r",
|
||||||
|
"apk", "search", query,
|
||||||
|
NULL);
|
||||||
|
XtFree(query);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stream == NULL) {
|
||||||
|
/* TODO: error popup */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
readPackageList(stream);
|
||||||
|
fclose(stream);
|
||||||
|
if (child != 0) waitpid(child, NULL, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void readPackageList (FILE *list) {
|
||||||
|
String line = NULL;
|
||||||
|
size_t lineLength = 0;
|
||||||
|
|
||||||
|
char packageName[256] = { 0 };
|
||||||
|
|
||||||
|
XmdBuffer *itemsBuffer = XmdBufferNew(XmString);
|
||||||
|
|
||||||
|
while (getline(&line, &lineLength, list) != -1) {
|
||||||
|
sscanf(line, "%256s", packageName);
|
||||||
|
free(line);
|
||||||
|
line = NULL;
|
||||||
|
XmString packageNameString = XmStringCreateLocalized(packageName);
|
||||||
|
XmdBufferPush(itemsBuffer, &packageNameString);
|
||||||
|
}
|
||||||
|
|
||||||
|
Cardinal length = XmdBufferLength(itemsBuffer);
|
||||||
|
XmStringTable items = (XmStringTable)(XmdBufferBreak(itemsBuffer));
|
||||||
|
|
||||||
|
XtVaSetValues (
|
||||||
|
packageList.list,
|
||||||
|
XmNitemCount, length,
|
||||||
|
XmNitems, items,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
/* free everything */
|
||||||
|
if (line) free(line);
|
||||||
|
for (size_t index = 0; index < length; index ++) {
|
||||||
|
XmStringFree(items[index]);
|
||||||
|
}
|
||||||
|
XtFree((String)(items));
|
||||||
|
}
|
||||||
|
|
||||||
|
void handleListModeSelectionChange (
|
||||||
|
Widget widget,
|
||||||
|
XtPointer clientData,
|
||||||
|
XtPointer callData
|
||||||
|
) {
|
||||||
|
(void)(widget);
|
||||||
|
(void)(callData);
|
||||||
|
|
||||||
|
int selected = *(int *)(&clientData);
|
||||||
|
packageList.viewMode = selected;
|
||||||
|
updatePackageList();
|
||||||
|
}
|
||||||
|
|
||||||
|
void handlePackageSelectionChange (
|
||||||
|
Widget widget,
|
||||||
|
XtPointer clientData,
|
||||||
|
XtPointer callData
|
||||||
|
) {
|
||||||
|
(void)(widget);
|
||||||
|
(void)(clientData);
|
||||||
|
|
||||||
|
XmListCallbackStruct *event = (XmListCallbackStruct*)(callData);
|
||||||
|
if (event->event == NULL) return;
|
||||||
|
|
||||||
|
String choice = (String)(XmStringUnparse (
|
||||||
|
event->item,
|
||||||
|
XmFONTLIST_DEFAULT_TAG,
|
||||||
|
XmCHARSET_TEXT,
|
||||||
|
XmCHARSET_TEXT,
|
||||||
|
NULL, 0,
|
||||||
|
XmOUTPUT_ALL));
|
||||||
|
selectPackage(parsePackageName(choice));
|
||||||
|
XtFree(choice);
|
||||||
|
}
|
||||||
|
|
||||||
|
void handleSearchQueryActivate (
|
||||||
|
Widget widget,
|
||||||
|
XtPointer clientData,
|
||||||
|
XtPointer callData
|
||||||
|
) {
|
||||||
|
(void)(widget);
|
||||||
|
(void)(clientData);
|
||||||
|
(void)(callData);
|
||||||
|
|
||||||
|
packageList.viewMode = viewModeSearch;
|
||||||
|
|
||||||
|
/* FIXME do this by activating the appropriate button. that way we dont
|
||||||
|
have to call updatePackageList manually as well. */
|
||||||
|
Widget button = XmOptionButtonGadget(packageList.modeMenu);
|
||||||
|
XtVaSetValues (
|
||||||
|
button,
|
||||||
|
XmNlabelString, packageList.viewModeStrings[packageList.viewMode],
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
updatePackageList();
|
||||||
|
}
|
||||||
|
|
||||||
|
String parsePackageName (String input) {
|
||||||
|
XmdBuffer *output = XmdBufferNew(char);
|
||||||
|
char ch;
|
||||||
|
Boolean wasDash = False;
|
||||||
|
for (size_t index = 0; (ch = input[index]); index ++) {
|
||||||
|
if (wasDash && isdigit(ch)) {
|
||||||
|
XmdBufferPop(output, NULL);
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
wasDash = ch == '-';
|
||||||
|
XmdBufferPush(output, &ch);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
char nullTerminator = 0;
|
||||||
|
XmdBufferPush(output, &nullTerminator);
|
||||||
|
return XmdBufferBreak(output);
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user